text:
analogRead DC Motor - Negative value
I was trying to play with Arduino this weekend and connected a DC motor to A0 and GND to measure the voltage it provides when I rotate it.
However,
when I rotate the DC motor with my fingers to test out the readings I see that when rotated clockwise it generates voltage that can be read in Arduino. But when I rotate it counter-clockwise the values I get are 0 - this is probably because DC motor generates negative voltage (?).
How do I fix this so that no matter the direction of the turn I get always positive value?
I am trying to build a simple anemometer, just for fun for kids and plot the values, however can't do much when I get 0 on analogRead when wind blows from the other direction..

thanks for any input into this.

What you're doing is a bit like using a DC motor as an AC generator. So to convert a negative voltage to a positive on in this case you can use a rectifier circuit (its basically an arrangement of  4 suitable diodes) or buy it ready made. The rectifier will make the voltage positive all the time which is what you seem to want-though youll probably need another circuit to sense the direction of the wind. A brushless DC motor is probably a good choice for making  an motor based anemometer.

anemometers only rotate in one direction, because of the shape of the cups. PS you might want to add a resistor between the motor and the Arduino pin, to prevent damage if the voltage is above 5V or below 0V. Something like 10kOhm.

Some anemometers do measure direction of wind e.g. see wikipedia

@qwerty10 some do, but not the one shown in the picture.

@Gerben, thank you - that makes sense to allow the motor to spin in only one direction. All i really need is to show kids if there was wind or not and how 'big' it was - no details, just a fancy color graph. Let me try that, thank you all for your help.

You can use full wave rectifier, but there is a significant voltage drop on it.
Another way is using Voltage divider to provide 1/2 Vcc to one of the motor terminals. But then you can measure just 1/2 Vcc in both directions (without another Voltage divider)
Something like:

This is probably the easiest solution. Other option is to go for the full wave rectifier but using an op amp to take care of the voltage drop. An example can be found at http://www.eleccircuit.com/full-wave-rectifier-with-an-op-amp-ic/.

I wouldn't connect a motor (or indeed any inductive circuit) to a semiconductor without protection. This should limit -ve as well as excessive voltages.
The simplest is to use clamp diodes to Gnd and 5V and connect the motor via a resistor. This will limit any incursions to one diode drop either side of the supply voltage, which should be safe.


text:
Which of the ESP8266 alternatives allows for full packet capture/injection in promiscuous mode?
I am part of a product group that is developing a low cost wireless intrusion detection system, for home usage.
We have already produced and delivered to market ESP8266 based product however for the new thing, we need the chipset to be able to enter promiscuous mode and receive/inject 802.11 packets on the fly without any limits.
ESP8266 is limited to 112bytes max, which is not enough to even parse the Beacon frame properly.
What are the alternatives for ESP8266 currently - that allow:

to capture the 802.11 frames
have no packet length limits
allow packet injection

Ps. doesn't have to be ARDUINO - but needs to be C/C++ programmable.
Thanks in advance.

Are you using encryption on your WiFi network?

Obviously, people do use encryption WEP(rarely)/WPA/2. Why do you ask ?

Because if you have encryption there is no such thing as promiscuous mode. You can't see anyone elses frames, they are encrypted. You want raw radio data access, and that then means manually decrypting packets to make any sense of anything.

Well you can still have promisc enabled and receive DATA packets that are encrypted. You can decrypt them later on if you know the key, not sure what's your point. Simply put, ESP does the job, but is limited with 112bytes which is not enough to perform full packet analysis.

That sounds more like direct radio data access than promiscuous mode.  If the ESP8266 can do it (kind of) then the ESP32 can most likely do it far better.

Unfortunately both 32 and 8266 have a limit set by ESPRESSIF for max length of a packet to 112 bytes. What does it mean? You get a MGMT Beacon frame length 239 bytes. All you can read is first 112 bytes, while in the rest of it you get trash...

Maybe something like the CC3100MOD would do the job. Not sure about programming it, but it has an ARM CPU embedded in it, so you can certainly use GCC. There's probably some toolkit available from TI from it. I've never used one, so I can't comment.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
What isthe best programming language for embedded systems?
I would start to learn the best programming language for embedded systems to control devices. What I have heard about that is Assembly Language. I want to know if there is any better languages to code for embedded systems?

This question is doubly off topic, first, because it is not about Arduino, and second because "what is the best" questions are off-topic on all stack exchange sites as a matter of general principle.

AFAIK, only assembly, C and sometimes C++ are supported by microcontrollers. VHDL or others by FPGA's. And then you also have PLC's with their languages.
Microprocessors (i.e) Raspberry Pi or other embedded PC's run almost anything.

Try to formulate a less "opinion based" question, and ask it on general Stack Exchange, since this isn't that interesting for Arduino.SE

What I have heard about that is Assembly Language - where from? C++ is much easier to learn, and compiles into efficient code. Asking about "the best" assumes you specify criteria. What is the "best" car to buy? Depends on how many people you plan to transport, how far you plan to go, your budget, etc. Asking for "the best" without specifying any parameters makes your question unanswerable. I'm going to close this question. Feel free to edit it with new information. Thanks for your understanding and cooperation!

Before your question gets closed:
There is no such thing as "the best"
Assembly
Assembly can be a very powerful language. But at the cost of some:

Assembly is different per machine. https://cs.stackexchange.com/questions/46935/is-a-universal-assembly-language-for-all-computers-possible
Assembly is somewhat less readable as other programming languages in my honest opinion.
I personally feel that assembly should only be used for optimalization rather than standard use of code.

C C can be as powerful as assembly, only when used correct. In fact, in C (and C++) you can actually inline assembly. https://en.wikipedia.org/wiki/Inline_assembler
C++ C++ is mostly backwards compatible with C, any C compiler (should?) be able to interpret/compile C code. Which also means you could use inline assembly.
C++ also comes with a lot of usefull tools, though, when used wrongly it can actually backfire you. (Which is with most programming languages that allow a lot, but also give you the possibility to do a lot)
I believe, that C++'s Object Oriented code, with the somewhat backward compatiblity and a little abstraction from the machine (being able to port it to other machines) would be the way to go.
Though, a good C/assembly programmer will out-play an average C++ programmer.
What about the other languages
C/C++ could be considered as the standard for embedded devices.
Best thing would be, to ask for individual programming languages, and why one would be better than the other. Or what the differences are.
I havent yet found anything that could "compile" Java for embedded devices. Java typically runs in a "run-time evironment". Which would come down to the fact that it needs an OS or atleast some resources for the code to be run-time interpreted.
C/C++ is also known for being "hard real-time" or atleast deterministic qua timing. Which is probably because of the same reason, not needing another layer and being pre-compiled. (And not having an runtime environment)
By these arguments, I believe C++ or C or Assembly would be the best. Or atleast most widely accepted.
You should check per project, which languages are known by your developers and which other requirements there are (porting to other platforms).
And it's a bit of a taste issue. I think Object Oriented code is very usefull. But some may see it as excessive/annoying.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Cat motion detector that can tell the difference from humans
I'm trying to build a cat motion detector but, to avoid getting false alarms when a person walks by, I was thinking of using RFID. i.e. the cat has a collar and the detector senses the collar when they get within a couple of feet and makes a noise.
The problem there seems to be with RFID is that the range is so short - e.g. 4".
Anyone have a better solution?

Where do you want to use it? Do you want detect when it goes though an door/corridor? More information would be helpful, as there is different kinds of motion detection. E.g. laser-tripwire, which you could place at different height similar to what  Dave X describes.

Place an additional motion sensor such that it can only detect motion from things significantly taller than cats, and use that as an inhibitor/classifier of the cat motion signal.

What about a transmitter on the collar - Bluetooth, or a coded infra red pulse, that could be detected by fixed stations?
Battery life and safety (swallowing batteries!) would be serious considerations though...

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Why doesn't OTA work with the Ai-Thinker ESP32-CAM board?
I have working code on an Ai-Thinker ESP32-CAM board, programming over serial.
I would like to reprogram using OTA, but adding in the functionality from the BasicOTA sketch (which I have done on various other boards successfully) fails when OTA programming is attempted, the board reboots following an abort() and a stack trace is generated.
The invaluable ESP32 exception decoder shows the fault occurs from checking if memory location is safe to write.
Normally, I would choose a partition option which includes OTA, but the Ai-Thinker board doesn't have this option in the IDE

The boards.txt file configures what can be configured in the Arduino IDE for each board.
On my installation, this is found at
C:\Users\MyUser\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\boards.txt
I found the section esp32cam.name=AI Thinker ESP32-CAM and changed the lines:
esp32cam.upload.maximum_size=3145728
esp32cam.build.partitions=huge_app

to
esp32cam.upload.maximum_size=1966080
esp32cam.build.partitions=min_spiffs

The various options are detailed in the same file with keys named esp32.menu.PartitionScheme., and for some boards these options are configurable be the user. To add this, remove (or comment out with a # character) the two lines found above so they look like:
# esp32cam.upload.maximum_size=3145728
# esp32cam.build.partitions=huge_app

and add the required menu selections for your application- e.g.
esp32cam.menu.PartitionScheme.huge_app=Huge APP (3MB No OTA/1MB SPIFFS)
esp32cam.menu.PartitionScheme.huge_app.build.partitions=huge_app
esp32cam.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
esp32cam.menu.PartitionScheme.min_spiffs=Minimal SPIFFS (Large APPS with OTA)
esp32cam.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
esp32cam.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080

After making any changes to boards.txt, restart the Arduino IDE for the change to take effect. Note that these changes (and any changes to the installation) may be overwritten by any future upgrades or library updates, so note your changes so they can be easily reapplied.
Alternatively, add the menu lines to boards.local.txt, introduced in Arduino 1.6.6 so they should persist during updates. In this case, no change needs to be made to boards.txt, as the boards.local.txt entries override those in boards.txt. I haven't tested this, hopefully it works across library updates and IDE upgrades.

You do not have to go through the hassle with editing the boards.txt if you want to have OTA only if you do not need it or you want a custom partition scheme.
That said the OTA partition is always what is left so e.g. Med Spiffs App 1.9MB, Spiffs 190KB means 1.9 MB OTA partiton.The caveat is if you want to OTA a 1.8 MB App with 1 MB Spiffs that will NOT work. The OTA file has to be around 100kb (from experience) smaller than the availabe OTA partition. If you want to update APP and SPIFFS thats a topic on its own. So before editing your boards.txt check the following:

App (uncompressed) is OTA space + ~100KB
your OTA routine runs stable with/in small apps
no connection problems during upload and
proper OTA error handling in your code
for initial testing attach no hardware to the board.
If using the unmodified camera example or a custom on with face recognition you will fail with OTA because this is to big (~3MB APP!)
OTA routines (incl wifi libs) take ~800 kB for basic OTA

As I use AIThinker32cam modules in various scenarios I know what you are through ;-)

Enclosed two custom board definitions (with no OTA) as there is no predefined (ESP32 core 1.04) in C:\Users\YOUR_USERNAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\boards.txt just copy and paste into the section (search for esp32AiThinkerCam.menu.PartitionScheme :
esp32AiThinkerCam.menu.PartitionScheme.noota_3g=1MB APP/3MB SPIFFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
esp32AiThinkerCam.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
esp32AiThinkerCam.menu.PartitionScheme.no_ota=2MB APP/2MB SPIFFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.no_ota.build.partitions=no_ota
esp32AiThinkerCam.menu.PartitionScheme.no_ota.upload.maximum_size=2097152

and the "magic unlocker" is the noota_3g.csv found in C:\Users\YOUR_USERNAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\tools\partitions,there the partition scheme isdefined. If you want to change that for custom partitions please ask a new question.EDIT
Enclosed acomplete boards.txt part for AI-Thinker just replace the complete existing part with this amd you have a bunch of new options - all tested in production with ESP32 core 1.04. (without custom partition schemes):
##############################################################

esp32AiThinkerCam.name=ESP32 AI Thinker Cam

esp32AiThinkerCam.upload.tool=esptool_py
esp32AiThinkerCam.upload.maximum_size=1310720
esp32AiThinkerCam.upload.maximum_data_size=327680
esp32AiThinkerCam.upload.wait_for_upload_port=true

esp32AiThinkerCam.serial.disableDTR=true
esp32AiThinkerCam.serial.disableRTS=true

esp32AiThinkerCam.build.mcu=esp32
esp32AiThinkerCam.build.core=esp32
esp32AiThinkerCam.build.variant=esp32
esp32AiThinkerCam.build.board=ESP32_DEV

esp32AiThinkerCam.build.f_cpu=240000000L
esp32AiThinkerCam.build.flash_size=4MB
esp32AiThinkerCam.build.flash_freq=40m
esp32AiThinkerCam.build.flash_mode=dio
esp32AiThinkerCam.build.boot=dio

esp32AiThinkerCam.menu.CPUFreq.240=240MHz (WiFi/BT)
esp32AiThinkerCam.menu.CPUFreq.240.build.f_cpu=240000000L
esp32AiThinkerCam.menu.CPUFreq.160=160MHz (WiFi/BT)
esp32AiThinkerCam.menu.CPUFreq.160.build.f_cpu=160000000L
esp32AiThinkerCam.menu.CPUFreq.80=80MHz (WiFi/BT)
esp32AiThinkerCam.menu.CPUFreq.80.build.f_cpu=80000000L

esp32AiThinkerCam.build.partitions=default
esp32AiThinkerCam.build.defines=-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue
esp32AiThinkerCam.menu.PartitionScheme.default=Default 1.2MB APP/1.5MB SPIFFS (OTA)
esp32AiThinkerCam.menu.PartitionScheme.default.build.partitions=default
esp32AiThinkerCam.menu.PartitionScheme.defaultffat=Default FATFS 1.2MB APP/1.5MB FATFS (OTA)
esp32AiThinkerCam.menu.PartitionScheme.defaultffat.build.partitions=default_ffat
esp32AiThinkerCam.menu.PartitionScheme.noota_3g=1MB APP/3MB SPIFFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.noota_3g.build.partitions=noota_3g
esp32AiThinkerCam.menu.PartitionScheme.noota_3g.upload.maximum_size=1048576
esp32AiThinkerCam.menu.PartitionScheme.no_ota=2MB APP/2MB SPIFFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.no_ota.build.partitions=no_ota
esp32AiThinkerCam.menu.PartitionScheme.no_ota.upload.maximum_size=2097152
esp32AiThinkerCam.menu.PartitionScheme.huge_app=3MB APP/1MB SPIFFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.huge_app.build.partitions=huge_app
esp32AiThinkerCam.menu.PartitionScheme.huge_app.upload.maximum_size=3145728
esp32AiThinkerCam.menu.PartitionScheme.noota_ffat=2MB APP/2MB FATFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.noota_ffat.build.partitions=noota_ffat
esp32AiThinkerCam.menu.PartitionScheme.noota_ffat.upload.maximum_size=2097152
esp32AiThinkerCam.menu.PartitionScheme.noota_3gffat=1MB APP/3MB FATFS (No OTA)
esp32AiThinkerCam.menu.PartitionScheme.noota_3gffat.build.partitions=noota_3gffat
esp32AiThinkerCam.menu.PartitionScheme.noota_3gffat.upload.maximum_size=1048576
esp32AiThinkerCam.menu.PartitionScheme.minimal=Min SPIFFS 1.3MB APP/700KB SPIFFS (OTA)
esp32AiThinkerCam.menu.PartitionScheme.minimal.build.partitions=minimal
esp32AiThinkerCam.menu.PartitionScheme.min_spiffs=Med SPIFFS 1.9MB APP/190KB SPIFFS (OTA)
esp32AiThinkerCam.menu.PartitionScheme.min_spiffs.build.partitions=min_spiffs
esp32AiThinkerCam.menu.PartitionScheme.min_spiffs.upload.maximum_size=1966080

esp32AiThinkerCam.menu.FlashMode.qio=QIO
esp32AiThinkerCam.menu.FlashMode.qio.build.flash_mode=dio
esp32AiThinkerCam.menu.FlashMode.qio.build.boot=qio
esp32AiThinkerCam.menu.FlashMode.dio=DIO
esp32AiThinkerCam.menu.FlashMode.dio.build.flash_mode=dio
esp32AiThinkerCam.menu.FlashMode.dio.build.boot=dio
esp32AiThinkerCam.menu.FlashMode.qout=QOUT
esp32AiThinkerCam.menu.FlashMode.qout.build.flash_mode=dout
esp32AiThinkerCam.menu.FlashMode.qout.build.boot=qout
esp32AiThinkerCam.menu.FlashMode.dout=DOUT
esp32AiThinkerCam.menu.FlashMode.dout.build.flash_mode=dout
esp32AiThinkerCam.menu.FlashMode.dout.build.boot=dout

esp32AiThinkerCam.menu.FlashFreq.80=80MHz
esp32AiThinkerCam.menu.FlashFreq.80.build.flash_freq=80m
esp32AiThinkerCam.menu.FlashFreq.40=40MHz
esp32AiThinkerCam.menu.FlashFreq.40.build.flash_freq=40m

esp32AiThinkerCam.menu.UploadSpeed.921600=921600
esp32AiThinkerCam.menu.UploadSpeed.921600.upload.speed=921600
esp32AiThinkerCam.menu.UploadSpeed.115200=115200
esp32AiThinkerCam.menu.UploadSpeed.115200.upload.speed=115200
esp32AiThinkerCam.menu.UploadSpeed.256000.windows=256000
esp32AiThinkerCam.menu.UploadSpeed.256000.upload.speed=256000
esp32AiThinkerCam.menu.UploadSpeed.230400.windows.upload.speed=256000
esp32AiThinkerCam.menu.UploadSpeed.230400=230400
esp32AiThinkerCam.menu.UploadSpeed.230400.upload.speed=230400
esp32AiThinkerCam.menu.UploadSpeed.460800.linux=460800
esp32AiThinkerCam.menu.UploadSpeed.460800.macosx=460800
esp32AiThinkerCam.menu.UploadSpeed.460800.upload.speed=460800
esp32AiThinkerCam.menu.UploadSpeed.512000.windows=512000
esp32AiThinkerCam.menu.UploadSpeed.512000.upload.speed=512000

esp32AiThinkerCam.menu.DebugLevel.none=None
esp32AiThinkerCam.menu.DebugLevel.none.build.code_debug=0
esp32AiThinkerCam.menu.DebugLevel.error=Error
esp32AiThinkerCam.menu.DebugLevel.error.build.code_debug=1
esp32AiThinkerCam.menu.DebugLevel.warn=Warn
esp32AiThinkerCam.menu.DebugLevel.warn.build.code_debug=2
esp32AiThinkerCam.menu.DebugLevel.info=Info
esp32AiThinkerCam.menu.DebugLevel.info.build.code_debug=3
esp32AiThinkerCam.menu.DebugLevel.debug=Debug
esp32AiThinkerCam.menu.DebugLevel.debug.build.code_debug=4
esp32AiThinkerCam.menu.DebugLevel.verbose=Verbose
esp32AiThinkerCam.menu.DebugLevel.verbose.build.code_debug=5

Thanks for the extra information, +1 for the detail. However the originally set huge_app setting for this board doesn't seem to leave any space for OTA (3MB app). I am using a small SPIFFS partition but that doesn't change the setting in boards.txt.

As I wrote the huge App 3MB can not be OTAed - there is nospace left toOTA you can use max 1.8MB APP or get a board with 8MB PSRAM - thats a hardware limitation not a software - try with  med asgiven in y text - if your App is larger reduce it or no OTA

huge_app is the fixed default for this board in the supplied boards.txt, which doesn't allow OTA as we both agree. It doesn't have a configurable option to choose min_spiffs, that's what I add below, maybe this is different from your installed esp32 boards.txt?

Sorry for the misunderstanding - choose ESP32 Wrover Module and use it for the Ai Thinker32Cam to flash, if you want to have an own menu copy the new part I posted above to your boards txt

Thanks for clarifying, I didn't know the Wrover and Ai-Thinker boards were interchangeable for programming, so that would be an alternative workaround in this case. Note for others who may be following - camera pinouts are different between the Wrover and Ai-Thinker modules (see camera_pins.h in the CameraWebServer example).

Using the ESP32 Wrover Module worked for me thanks. The pin definitions are inline in the app so no problem with those.

As stated in the comments by @Codebreaker007 using the ESP32 Wrover Module works and if you put the pin definitions inline in the app there isn't a problem
#define CAMERA_MODEL_AI_THINKER

#if defined(CAMERA_MODEL_AI_THINKER)
  #define PWDN_GPIO_NUM     32
  #define RESET_GPIO_NUM    -1
  #define XCLK_GPIO_NUM      0
  #define SIOD_GPIO_NUM     26
  #define SIOC_GPIO_NUM     27

  #define Y9_GPIO_NUM       35
  #define Y8_GPIO_NUM       34
  #define Y7_GPIO_NUM       39
  #define Y6_GPIO_NUM       36
  #define Y5_GPIO_NUM       21
  #define Y4_GPIO_NUM       19
  #define Y3_GPIO_NUM       18
  #define Y2_GPIO_NUM        5
  #define VSYNC_GPIO_NUM    25
  #define HREF_GPIO_NUM     23
  #define PCLK_GPIO_NUM     22
#else
  #error "Camera model not selected"
#endif

Here.
Download this working ESP32-CAM sketch zip file with working OTA uploading:
"Working_ESP32_CameraWebServer_V2_with_OTA"
at
https://github.com/wjsanek/wjsanek.git
Make sure you read the simple "READ ME FIRST" file in the zip after unzipping.
This sketch overcomes any "file to big" or other OTA sketch uploading problems with this crumby, tempremental ESP32-CAM board (the $5 ESP8266 NodeMCU is better but the Arducam camera for it costs $23).
The ESP32-CAM board does not like to transmit very far.

OTA Requires you to partition your ESP32 with two sets of space for your program (ota_0 and ota_1 partitions) - during the OTA process, the unused one gets updated, and will be the next one that boots up.
This means that there's no room left for the camera (most camera driver libraries store the image in SPIFFS) to store the image data (OV2640 is 1622x1200 pixels, which is 1946400 bytes) because the only available partition schemes with OTA in Arduino IDE is 1.9mb program with 0.19mb (190kb) SPIFFs, which is 10-times-not-enough space to store camera images in.
the wjsanek project in here looks interesting - they're using one of the OTA partitions as the SPIFF for the camera. Very clever.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
How to implement a 2D lookup table?
This is my first post to this forum.  I am fairly experienced in electronics, but am in the process of learning C, Arduino coding, and how to use microcontrollers in general for various applications.
I have a toy-like 5 degree of freedom (DOF) robot arm that is currently controlled using the OEM hand-held switch box.  It is a basic electromechanical robot arm to illustrate the fundamentals and it uses DC motors to drive the joint motions.  The direction of motion is controlled by changing the polarity of the applied voltage.  The manufacturer did offer an "interface board" and SW to be able to hook up the arm and control it using a computer program.  However, this approach was fairly dated and their SW was not compatible with windows 8.1.  I wanted to experiment and use an Arduino Uno Rev 3 and 5V DC relay PCBs to develop my own interface system.
Basically, the HW aspect was straightforward and is working fine.  The Arduino SW also is working fine.  I am playing around with 2 variations of the program: 1) One program that simultaneously moves up to 3 joints and 2) A sequential joint movement program where each joint only moves after the other has finished moving.  One note about the simultaneous program is that I am using the "internal" batteries in the robot's base (only 3V each direction) and thus can not realistically move more than 3 joints at the same time without putting too much load on the source voltage.
Ok, now to my question! As it stands now, the program works well, but is not intuitive.  Each joint has 2 relays associated with it: one for each direction of travel.  There are 5 joints total in the robot arm.  I am able to use the program easily since I know directly (from setting up the HW and then the SW) which relays correspond to which Arduino pins and of course which relays correspond to each joint.  I'd like to make the program more intuitive where instead of "2,2,0,0,3,4" input string for example, the user would do something like "B,CCW,S,CW"  where B is for B = base, CCW = is counter clockwise etc.
Please note that in the numerical only input string "2,2,3,4" for example, the 2nd value corresponds to the duration in seconds that the relay will be ON (and thus the joint moving).  The robot arm is not very sophisticated in that it doesn't have encoders for position feedback.  The simplest way (and the method which the OEM interface board uses) to interface this arm and make a program where the arm will move in a "hands-off fashion" was to use relays and program delays (to create time durations of joint movement".  The numerical only input works really well currently and it was very easy to use examples to figure out how to parse a comma separated string.
I understand (I think) from looking at the examples how to parse a comma separated text string and pull from it the input values.
BUT, I am uncertain how to use those input values and then associate them in the SW with the correct relays (Arduino Pins)!
I have already tried seeking help with this but am unable to understand this thread:  http://forum.arduino.cc/index.php/topic,94701.0.html
Basically, I need a 2D table where the joint and direction are input and then the SW associates one particular relay with those inputs. Please see the table below for a graphical example of what I tried to say above.
One possible solution that I dread and saw mentioned was to use a ton of if else-if statements....  I dread this since I want to be able to input any joint in any order and thus it seems like when the code parses the input string for the ith relay, it would have to check ALL of the conditions to see which joint it is, which direction etc.  For example, I think I could minimize the # of if statements needed if I only entered in the input commands in a certain order: base first, shoulder next, etc.  Doing so however, limits the intuitiveness of the program.

Thank you all for reading this!  I hope this isn't too challenging!

@Edgar Bonet, JRobert and Majenko Thanks for the prompt replies!  I will sandbox the example code you provided.  I have a feeling that one method may be easier to use for my program that takes command inputs through the Serial Monitor and another method for the hard-coded sequential moment program.  In the hard coded program, by having the code contain abbreviated references to the joint and direction, it will make it easier to understand since it now simply contains numerical arrays of relay order, ON duration, delay after each movement, etc.

I suggest you turn this into a simple 1D table by using two different
separators, for example ‘:’ between joint and direction, and ‘,’ between
consecutive movements. Then, instead of “B,CCW,S,CW” you would type
“B:CCW,S:CW”. For parsing the string, you split at the commas, and
consider the pieces between the commas as single items. In other words,
“B:CCW” would be the name for relay 2, and you do not try to split it
further.
Here is a simple method to map the strings to the relays:
const char * const relay_names[] = {"", "B:CW", "B:CCW", "S:UP",
    "S:DN", "W:CW", "W:CCW", "E:UP", "E:DN", "G:OP", "G:CL"};

// Return the relay number.
int get_relay(const char * name)
{
    for (int i = 1; i <= 10; i++)
        if (strcmp(name, relay_names[i]) == 0)
            return i;
    return -1;  // meaning invalid
}

I selected this method because it seemed more intuitive imo to input commands in the serial interface that had direct correlation with the joint name and movement direction.  I appreciate the other answers for showing alternative methods of achieving the same goal.

Another thing you can consider is to define a struct.  This is a compound variable that contains other variables of different types.
You could define a struct to describe the joints of an arm:
struct arm {
    int base;
    int shoulder;
    int elbow;
    int wrist;
    int grip;
};

Which you can then assign as variables:
const struct arm left_forward = { 1, 3, 7, 5, 9};
const struct arm left_reverse = { 2, 4, 8, 6, 10};

You can then get at different pins by using such things as:
digitalWrite(left_forward.shoulder, HIGH);

Another trick is to make your struct contain a union and an anonymous struct so you have multiple ways of accessing the pins:
struct arm {
    union {
        struct {
            int base;
            int shoulder;
            int elbow;
            int wrist;
            int grip;
        };
        int pins[5];
    };
};

You can now get at left_forward.shoulder and left_shoulder.pins[1] and they point to the same thing.
You can create an array of these structures now:
const struct arm left[2] = {
    { 1, 3, 7, 5, 9},
    { 2, 4, 8, 6, 10}
};

So now you have left[0].shoulder and left[0].pins[1] both for the left shoulder moving forwards.
Another option, which might be far more logical, is to turn the whole thing inside out.  Define a "pin pair" structure that defines the two pins for a joint:
struct pinpair {
    int forward;
    int reverse;
};

Then an arm consists of 5 "pin pairs":
const struct pinpair leftarm[5] = {
    {1, 2},
    {3, 4},
    {7, 8},
    {5, 6},
    {9, 10}
};

So to move the left shoulder forward it would be leftarm[1].forward and to move the wrist backward would be leftarm[4].reverse.
Of course, you could combine the two and have a struct of named structs for each joint if you wanted (leftarm.shoulder.reverse. I'll leave you to work out the syntax for that from the examples above).
Now for your "control string".  How to deal with that.  Well, I would "pre-parse" it into an array of numbers.  Compile it into "byte code" if you will.
Start with an empty array that would be big enough to store the data you want, then work your way through the string.
Tokenize it (hint: strtok() is good for this) and check each piece of the string against others.  Unfortunately it's not something you can easily automate, and you'd either have to loop through an array of strings to compare each one to, or use a series of "if" statements.
For each item that you match you then assign a "command code" to - a number you can then easily associate with a specific action or joint.  For instance, "B" may equate to command 0, "S" to 1, ""E" to 2, etc - which just happen to coincide with the array slices for the joints.
The directions could then be other codes (keep them outside the range of your array so you can identify them), maybe 16 and 17 (hint: think about the hexadecimal representation of those and how you could use that to your benefit).  It can also be useful to mark the end of the array with a special token to say "this is the end" - say 255 (0xff).
Then once you have parsed the string and got your list of numbers, which may be something like { 0, 16, 1, 17, 255 }, you can then "execute" it.  Just step through each entry, if it's < 16 then it's a command, if it's >= 16 then it's a direction, and if it's == 255 then it's the end of the command list.  It's then up to you to drive the right pins for the right periods to execute those commands.

In C/C++, multi-dimensional arrays are represented as arrays of arrays of arrays ..., for the number of dimensions needed (the last subscript varying most rapidly as you step through the stored elements in RAM).
The array you described is a sparse array; not all cells hold valid data. To simplify (and that's a relative term!) the storage and the code, I would arbitrarily assign each joint a forward and a reverse direction, reducing your 10-row sparse array to a dense array of only 2 rows. You can then, if you wish associate joint-relative motionss (up/down, open/close, etc.) with forward/reverse. Then you can find the pin # for a given joint relay by the joint name and direction as RelayPin[<direction-name>][<joint-name>]. A downside is that writing RelayPin[DIR_OPEN][JNT_ELBO] looks like nonsense but actually executes, though maybe not in the direction you think you meant.
This code snippet defines a 2D array of joint-relay pin numbers, with an example of enabling one of the relays:
// Number of joints and directions
#define NDIRECTIONS 2
#define NJOINTS 5

// Basic joint-motion directions
#define _DIR_FWD 0
#define _DIR_REV 1

// Aliases for joint-motion directions
#define DIR_CW _DIR_FWD
#define DIR_CCW _DIR_REV

#define DIR_UP _DIR_FWD
#define DIR_DN _DIR_REV

#define DIR_OPEN _DIR_FWD
#define DIR_CLOSE _DIR_REV

// Joint table indices
#define JNT_BASE 0
#define JNT_SHOU 1
#define JNT_ELBO 2
#define JNT_WRIS 3
#define JNT_GRIP 4

// Joint table - each element is a digital pin number
uint8_t const RelayPin[DIRECTIONS][JOINTS] = {
//  B  S  E  W  Ga
   {1, 3, 7, 5, 9}, // forward
   {2, 4, 8, 6, 10},    // reverse
};

// Example of enabling motion to raise the shoulder:
digitalWrite(RelayPin[DIR_UP][JNT_SHOU], HIGH)  // raise shoulder

The other answers have presented some good techniques that are flexible enough to be adapted to other, similar problems.  By contrast, the following method is specialized to work with the particular chart of joint-letters and relay-numbers mentioned in the question.  (It can be modified for other relay-number sequences, as noted in program's comments.)
Rather than requiring entry of verbose text like CCW, or obscure abbreviations like DN, OP, and CL, it accepts a + or a - to set motor direction, with “+” corresponding to choices CW, UP, and OP, and “-” corresponding to  other choices.  For example, the question's sequence “B,CCW,S,CW” could be written as any of “B-S+”, “b-s+”, “B- S+”,  “B-,S+”, etc (ie, case is ignored, and spaces and commas are ignored before a joint-letter).
Note, the code as shown assumes each command-list line starts with a number that gives desired delay time in tenths of a second.  For example, “23 e-s+” would run E down and S up for 2.3 seconds.  The command-list “47” would sit idle (no motors on) for 4.7 seconds.
#include <ctype.h>
void operateRelays(char *cmdList) {
  char *joints = "BSEWG", *c=cmdList, *j;
  byte relay, delaytenths= 0;

  while (*c && isdigit(*c)) // Get # of tenths-of-seconds to delay
    delaytenths = 10*delaytenths + *c-'0';

  for (; *c; ++c) {
    while (*c && !isalpha(*c)) ++c; // Ignore non-alphas before joint
    if (!*c) break;     // At end of command list, break
    for (j=joints; *j; ++j)
      if (toupper(*c) == *j) break;
    if (!*j) break;     // Ab-exit if joint-letter not found
    if (!*(++c)) break;     // Advance to + or -
    relay = 2*(j-joints) + 1 + (*c != '+'); // The last term is 0 or 1
    digitalWrite(relay, HIGH);
    // If relay numbers aren't contiguous as in question, just use
    // an array (like: byte relays[] = {2,1,5,4,6,3,7,9,10,8};)
    // and in above statement say digitalWrite(relays[relay-1], HIGH);.
  }
  delay (100*delaytenths); // Wait specified time
  for (relay=1; relay<11; ++relay) // Turn motors off
    digitalWrite(relay, LOW);
}


text:
Unsure about how the code works for this Make-It Robotics kit
I have been using a Make-It Robotics kit, that I picked up from a RadioShack that was closing, to learn more about Arduino, C, etc.  After building the line-following robot and downloading the correct libraries, I can get the robot to function as intended.  It uses 2 optical sensors in front of 2 driving wheels that are controlled by independent DC motors.  The optical sensors determine if the left or right side of the front of the robot is over a white or black area on the test track. The necessary motor then turns on to keep the black line roughly between the 2 sensors as the robot moves along. The default test track that came with the kit was a large black circle on a white background.
I want to make some modifications to the code (and maybe the underlying library files) to try to make the robot able to handle other types of paths with more acute angles and sharper turns, etc.  But, I don't understand some aspects of the highest level .ino source code file.
I am a little unsure of pasting such a long code block below and also don't think an image of it will help.  The version data for the file I'm using is below.  The files can be found online @ LINK
// ******************************************************************************    **
// * File Name          : linefollow
// * Author             : RadioShack Corporation
// * Version            : V1.0
// * Date               : 2014/01/16
// * Description        : Optical sensors send feedback to PCB
// *                      to make the robot follow a black line on a white background.
// ********************************************************************************

In this .ino file, I don't understand the code from line 68 onwards: from the Read Left/Right Optical Status onward...
I don't understand some of the bitwise operations there and don't really see how the sensor readings (whether it is over a white or black area on the surface) correlates to which motor activates to keep the robot on the course...
From my limited understanding of Arduino, this robot kit, and the code, it seems like the software and hardware have to interact in this way:

Robot moves forward using both motors turning the wheels in the same direction.  It approaches the black test circle at a shallow angle (i.e. almost tangent to it) to allow one sensor to go over the black line before the other one does.
Optical readings of each sensor are taken periodically.
If both sensors detect white space, robot continues to move forward.
If the right sensor detects that it has gone from white to black and then to white, it means that the robot needs to turn to the left to stay on the path.
To turn left, the left motor is un-powered and the right motor is powered until the right sensor detects black again.
Now that the robot is on course, it will keep turning in the direction of the sensor that detects a white to black to white transition.

I am not seeing how my intuitive understanding of the robot's operation matches with that of the code...

The files can be found online. - Where online...?

@Majenko Please see added LINK in original post.  The original "OEM" link that came with the kit's manual gave Error 404, so another site had the files.

Indeed, the way the bitwise operations are written is confusing.
  if((sensor_in & 0xf00)==0)
    sensorValue1=sensor_in & 0xff;
  else if((sensor_in & 0xf00)>>8==1)
    sensorValue2=sensor_in & 0xff;
  if (sensorValue1 == 0x00)
    action1 =action1 & 0xfe;
  if (sensorValue1 == 0xFF)
    action1 = action1 | 0x01;
  if (sensorValue2 == 0x00)
    action1 = action1 | 0x02;
  if (sensorValue2 == 0xFF)
    action1 = action1 & 0xfd;

Basically you have two input values that can be in the same variable - differentiated by the 9th bit of the value.  Values between 0 and 255 relate to one sensor, between 256 and 511 to the other.  The bitwise operators split that into sensorValue1 and sensorValue2 accordingly.
Then those sensor values are compared to 0 or 255 and used to define the action to perform - that action being comprised of the lowest two bits of a byte variable, so you have three possible actions:
0 = both sensors off
1 = sensor 1 on, sensor 2 off
2 = sensor 1 off, sensor 2 on
3 = both sensors on

The comments in the program also tell you this information:
action1
         left        right
0x00    black        black
0x01    black        white
0x02    white        black
0x03    white        white

Now you have how to deal with the action value:
if(action1 != action2)
{
  if (action1 == 3 )
    line_following.go_forward(50);
  if (action1 == 1)
    line_following.line_following_turn_left(50);
  if (action1 == 2)
    line_following.line_following_turn_right(50);
  if (action1 == 0)
    line_following.go_forward(50);
}
action2=action1;

So if the action has changed, we can change what we are doing:

If action is 3, so if both sensors read as white, or if action is 0, so both sensors read black (in other words if both sensors read the same) then move forwards.
If action is 1 (so the left sensor reads black) then turn to the left.
If action is 2 (so the right sensor reads black) then turn to the right.

So basically if it doesn't know anything better, it drives forwards, otherwise it turns in the direction that it finds the black line, thus keeping it always on that line.  As it drifts off the line one sensor will sense white, so the robot will turn away from that whiteness and back on to the line.

Thanks for taking the time to answer my questions.  What tripped me up at first was all the values being in Hex and the bit-wise math.  I had to read up on bitwise math on the Arduino reference website.

In addition to the answer given on this site, I had to do some reading up on what bit-wise operations are and how they are useful.  I did most of that reading on the Arduino website reference section.
I also stumbled across an online tech blog that actually dissected the inner workings of this program!  The blog's author seemed glad to help Arduino beginners who got this kit, but had trouble understanding how exactly the robot moved in response to the sensor data.
JoesTechBlog
Someone even asked the blog's author about why anyone would code the logic in this manner.  I too was wondering the same as to why it wasn't done at a higher (thus easier to understand level).  Below is the author's response to that question.  Can anyone here comment on it in terms of its veracity?

Hello Richard, Yes I agree this logic is non-intuitive. I would have done the >logic on the mirco-controller, that lives on the driver board, and just had >the read_Optical() method return a 0, 1, 2, or 3. But there is one possible >reason for this logic. Performing bitwise operations in most cases takes up >less CPU cycles than complex number comparisons. Since Radio Shack is not >providing us the source code that runs on the driver board. Then we can only >guess. Also sometimes bare metal programmers think in these terms, which may >seem non-intuitive at times, but the more we start working at the bit level >the more it makes sense.
Thanks for the post.
Joe


text:
Multiple variant.cpp entries for same physical pin
Some variant.cpp files have more than one entry that points to the same physical pin. For example (from Arduino Zero's file):
// 14..19 - Analog pins
// --------------------
{ PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // ADC/AIN[0]

...

// 43..45 - Alternate use of A0 (DAC output), 44 SWCLK, 45, SWDIO
{ PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, DAC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // DAC/VOUT

The first entry sets up the pin as a regular analog input pin on A0. The second entry sets it up as a DAC on pin IDE pin 43.
The corresponding variant.h file defines the DAC pin and A0 as entry 14, rather than 43. I also have seen plenty of examples online that use the DAC via A0 when working with an Arduino Zero.
/*
 * Analog pins
 */
#define PIN_A0               (14ul)
#define PIN_A1               (15ul)
#define PIN_A2               (16ul)
#define PIN_A3               (17ul)
#define PIN_A4               (18ul)
#define PIN_A5               (19ul)
#define PIN_DAC0             (14ul)

Finally, I see other variants, like this one that don't even bother to create a DAC-specific entry. So presumably it doesn't actually matter? If not, then why is it in the Arduino Zero variant.cpp file at all?
A related question: How does using a pin for multiple purposes work? For instance, if I had a pin I've configured for SPI MOSI (in variant.cpp), and I wanted to also use it for PWM (given the datasheet says the pin is on a SERCOM and a timer), do I actually need two entries in variant.cpp and thus two different IDE pins to use in my sketches (one that has a pin type of PIO_SERCOM and another with PIO_PWM)? I can think of plenty of times working with an Arduino UNO, for instance, where I've just used the same IDE pin number for general IO as well as SPI (MOSI).

The analogWrite function checks the PIN_ATTR_ANALOG attribute from pin description in variant.cpp to determine if the pin has DAC capability. Then it checks if the pin is ADC_Channel0 or DAC_Channel0. This is unnecessary and redundant. There is no other use for DAC_Channel0.
In Arduino SAMD core and derived cores the pin 'map' in variant.cpp defines pin capabilities used by Arduino core. It is not a complete copy of the mux table from the datasheet. In some variant.cpp files comments contain the additional mux options of the pin.
For PWM the analogWrite function configures the pin and for SPI, the SPI library configures the pin.
If you want to use the pin for other SERCOM function, the function pinPeripheral is used to set up the pin. Here is a tutorial.
Arduino core doesn't support a configuration of a different wave output then analogWrite. To configure a different wave output or capture, a third party library or direct registers configuration is necessary.
The Arduino pinPeripheral(pin, peripheral) function uses the variant.cpp mapping and the possible parameters are:
PIO_EXTINT=0,     /* The pin is controlled by the associated signal of peripheral A. */
PIO_ANALOG,       /* The pin is controlled by the associated signal of peripheral B. */
PIO_SERCOM,       /* The pin is controlled by the associated signal of peripheral C. */
PIO_SERCOM_ALT,   /* The pin is controlled by the associated signal of peripheral D. */
PIO_TIMER,        /* The pin is controlled by the associated signal of peripheral E. */
PIO_TIMER_ALT,    /* The pin is controlled by the associated signal of peripheral F. */
PIO_COM,          /* The pin is controlled by the associated signal of peripheral G. */
PIO_AC_CLK,       /* The pin is controlled by the associated signal of peripheral H. */
PIO_DIGITAL,      /* The pin is controlled by PORT. */

If you are good with the Arduino variant.cpp configuration, then for direct registers access configuration the pin 'map' from variant.cpp and the pinPeripheral function can be at help if the pin should not be hardcoded. Example from peripherals setup for 'phase cutting' with a Triac in my project:
const PinDescription& pinDesc = g_APinDescription[triacPin]; // Arduino pin description
TCC = (Tcc*) GetTC(pinDesc.ulPWMChannel);
uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel);
bool periF = (pinDesc.ulPinAttribute & PIN_ATTR_TIMER_ALT);

// setup the pin as TCC wave out pin
pinPeripheral(triacPin, periF ? PIO_TIMER_ALT : PIO_TIMER);

TCC->CC[tcChannel].reg = PULSE_PERIOD;

Thanks for your response. It doesn’t quite answer the question though about how a variant could get away with not specifying the DAC alternative for A0 (PA02). For instance, the A0 entry doesn’t even specify the DAC channel as the alternate entry does. If A0 were passed to some function that ultimately looks at the channel configuration, it wouldn’t have the right value.

sorry, I missed the ADC_Channel0/DAC_Channel0 difference. I enhanced the answer with a new first paragraph

Thank you! A small side question: What is the consequence of having two different pins on the same timer and channel? For instance, on the SAMD21E, both PA06 and PA30 (SWCLK) have TCC1/WO[0] as the only timer option in the SERCOM mux table.

SERCOM is SERialCOMunication so UART, SPI, I2C. you can't set two different pins on the same timer and channel. you can map them on the same timer and channel, but then they can't be used at the same time for PWM


text:
ADC register always returning high
Regardless of whatever voltage at A0, the software is always returning high (1023)
volatile unsigned char* ADmux = (unsigned char*) 0x7C;
volatile unsigned char* ADCSRa = (unsigned char*) 0x7A;
volatile unsigned char* ADCSRb = (unsigned char*) 0x7B;
volatile unsigned char* ADCh = (unsigned char*) 0x79;
volatile unsigned char* ADCl = (unsigned char*) 0x78;
int Voltage;

void adc_init()
{
  *ADmux = 0x00; // setting entire register to 0's notably setting Refs1 and refs0 to 0's meaning reference voltage is AREF
  *ADCSRa = 0b10000111; //Sets most significant bit to 1, which is the ADC enable bit, and the 3 least signifcant bits are the prescalar, which is 128

}

unsigned int adc_read( unsigned char adc_channel)
{
  *ADmux = *ADmux | 0b00000000;// set mux bits to 0 to test A0 regardless of whatever adc_channel is
  *ADCSRa = *ADCSRa | 0b01000000; // set ADSC bit high to start conversion

  while(*ADCSRa & 0b01000000);//wait until ADSC goes low, indicated conversion is complete

  return ADC; //return bits in the adc registers
}

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);
   adc_init(); // initializes the adc
}

void loop() {
  // put your main code here, to run repeatedly:

  Voltage = adc_read(0b00000); // calls on adc_read

  Serial.print(Voltage); // prints voltage reading
  Serial.write("\n");

}

And here is a schematic of the circuit:

simulate this circuit – Schematic created using CircuitLab
I have combed over chapter 26 of the atmega2560 document and the descriptions of each register, but I am at a loss. Why is the contents of the adc registers always filled with 1's regardless of the voltage at a0?

what do you read if you remove R1?

@jsotola it still reads 1023

What IDE do you use, if any? Make sure MUX5, at ADCSRB:3 is set to 0, as well as ADTS2:0 at ADCSRB 2:0 to enable free running mode.

I got the program to work by setting refs0 to 1. So this means that the reference voltage switched from AREF to AVCC. Does anyone know why this small change makes it work? Isn't AREF 5V by default?

@towe I'm using the default Arduino IDE.

First, let me give a couple of suggestions on the programming style.
There is no point in defining your own variables for accessing the
hardware registers: the avr-libc does that for you, you just have to
#include <avr/io.h>. Actually, you don't have to #include anything:
the Arduino IDE automatically #includes Arduino.h, which in turn
#includes avr/io.h.
Next, the same avr-libc also defines macros for the bit names, so you
don't have to explicitly write binary numbers in your own code (which is
error-prone). And a couple of utility macros that you can use to make
the code a little bit more readable. For example:
void adc_init()
{
    ADMUX  = _BV(REFS0);  // ADC reference = AVCC
    ADCSRA = _BV(ADEN)    // enable the ADC
           | _BV(ADPS2)   // set prescaler to 128
           | _BV(ADPS1)   // ditto
           | _BV(ADPS0);  // ditto
}

unsigned int adc_read(unsigned char adc_channel)
{
    ADMUX   = _BV(REFS0) | (adc_channel & 7);  // select channel
    ADCSRA |= _BV(ADSC);  // start conversion

    // Conversion is complete when ADSC goes low.
    loop_until_bit_is_clear(ADCSRA, ADSC);

    return ADC;  // return the adc data register
}

Now, let's answer your actual question. When you set both REFS0 and
REFS1 to 0, the voltage reference is stated to be “AREF, internal V
REF turned off”. The implication is that you are supposed to bring your
own voltage reference and connect it to the AREF pin. Otherwise AREF is
left as a floating input. This is illustrated in the schematic of the
ADC. Here is the relevant part:

As you see here, REFS0 is used to connect AREF to one of the other
possible references: either AVCC or the internal bandgap. If REFS0 is
zero, the transistor depicted above is off, and AREF is left floating.

What are the resistance values for R1 and LDR1? Their ratio will determine the voltage at A0. If the ratio of their resistances is too high (for example, 100:1) then any light measured by LDR1 would only result in a small change in the voltage being measured. If the difference is extreme enough, the voltage could also appear to be constantly low or high. If you have a multimeter available, checking the voltage of that divider circuit could help determine what's going on.
https://learn.sparkfun.com/tutorials/voltage-dividers/all


text:
problem with reading PS3 controller buttons
I'm working on a camera slider mount with an X stepper (to move along slider), Y stepper (pan left right) and Z stepper (tilt up down). All of this is being controlled by a PS3 controller (PS3BT library).
I've implemented a feature in which all three steppers move from one saved position to other and then back again.. this keeps repeating infinitely. It works fine - except I can't stop it - it's more of a programming issue I think. Here's the code in question
// MultiStepper instance - at the top somewhere
MultiStepper StepperControl;

void loop(){
    if(PS3.getButtonClick(START)){ // START to start movement between two POS's.
        Serial.print("\n Starting Movement between POS1 and POS2");
        while(!PS3.getButtonClick(CROSS)){
          StepperControl.moveTo(POS1); // go to POS1
          StepperControl.runSpeedToPosition();
          delay(200);
          StepperControl.moveTo(POS2); // go to POS2
          StepperControl.runSpeedToPosition();
          delay(200);
        }
      }
}

My issue is that pressed X (cross) on the keypad, doesn't quit out of the loop. What I feel is happening is that the loop is running too fast and all the moveTo() commands are stacking on top of each other. And so, even if I do press X, too many moveTo() commands have already happened and it just keeps running those "queued" commands.
I've also tried putting an if statement inside the while loop that breaks out of the loop when CROSS is pressed - no luck.
// This isn't the entire code, just the parts I think are relevant.

you need to identify the problem correctly before you can arrive at a solution ..... the description of your problem has nothing to do with the AccelStepper Library - moveTo() ..... remove all the stepper code from your sketch (or start a new sketch) .... keep the PS3 code and use serial.print() to debug your code ..... determine which code you need, to correctly detect which buttons are being pressed

The while(!PS3.getButtonClick(CROSS)) is only checked once per loop, so your system will complete a move to POS1, wait 200ms, complete a move to POS2, and wait another 200ms before it can check the controller for another button press.
runSpeedToPosition() is "blocking", which means NOTHING else can happen while it is doing it's task.
Instead, you probably want to avoid blocking functions and set up a finite state machine and use the run() function of AccelStepper, which you should call as often as you can and it will move the stepper one step toward the target position, if it's not yet at the target position.
The following rewrite is not tested, but the general structure should show you how you can change the way the program is written. You should think of the loop() function running and completing a million times a second, and each time through, you check the state (that is, on what step is the system currently on) and act accordingly. Change to a new state when appropriate.
In the example, there are 5 states, corresponding to all possible combinations of what your program could be doing:

STOPPED: the initial state, the stepper has no target
RUNTO1: the stepper is moving toward POS1, but hasn't reached it yet
WAIT1: the stepper has reached POS1 and is now waiting for a specified delay before moving to the next state. This state uses the process shown in the BlinkWithoutDelay standard Arduino example sketch for delaying without blocking.
RUNTO2: the stepper is moving toward POS2, but hasn't reached it yet
WAIT2: the stepper has reached POS2 and is now waiting for the next state

You can also see the situations where a state is changed:

When START is pressed, set a new target position and enter the
RUNTO1 state
When CROSS is pressed, stop all stepper action and enter the STOPPED state
When in RUNTO1 or RUNTO2, and the distanceToGo() is zero, enter to the corresponding WAITn state
When in the WAITn state and the specified time has elapsed, enter the corresponding next RUNTOn state.

Example:
#define POS1 80
#define POS2 0

const uint16_t DELAY = 200;
enum stepperstates {STOPPED, RUNTO1, WAIT1, RUNTO2, WAIT2};

[...]

void loop() {
  static uint16_t last_millis;
  static stepperstates xStepState;
  if (PS3.getButtonClick(START)){
    xStepState = RUNTO1;
    StepperControl.moveTo(POS1); // go to POS1
    Serial.print("\n Starting Movement between POS1 and POS2");
  }
  if (PS3.getButtonClick(CROSS)) {
    xStepState = STOPPED;
  }

  StepperControl.run();

  switch (xStepState) {
    case STOPPED:
      StepperControl.stop();
      break;
    case RUNTO1:
      if (StepperControl.distanceToGo()==0) {
        xStepState = WAIT1;
        last_millis = millis();
      }
      break;
    case WAIT1:
      if (millis() - last_millis >= DELAY) {
        xStepState = RUNTO2;
        StepperControl.moveTo(POS2);
      }
      break;
    case RUNTO2:
      if (StepperControl.distanceToGo()==0) {
        xStepState = WAIT2;
        last_millis = millis();
      }
      break;
    case WAIT2:
      if (millis() - last_millis >= DELAY) {
        xStepState = RUNTO1;
        StepperControl.moveTo(POS1);
      }
      break;
  }
}

Ahh. That makes so much more sense. So basically with my original code - the user got almost no chance to even press X because delay() was blocking and so was the moveToPosition(). And now with this code - run() is not blocking and each time run() happens, we check if X was pressed and if so enter the STOP state.


text:
limit switch and external interrupt
The INT0 pin of a custom Arduino-like board based on Atmega16 is configured in INPUT_PULLUP mode and connected to a N.O contact of a limit switch, the other end of the switch is connected to GND.
in the main loop an ac motor is activated each hour, and stops when hitting the limit switch:
void loop()
{
.....
.....
if((millis() - lastT) >= ONE_HOUR) {
    GICR &= 0xBF;  //disable INT0 interrupt
    digitalWrite(MOTOR_PIN, HIGH);
    lastT = millis();
  }
delay(5000); //time for motor to quit the limit switch
GICR |= 0x40;  //enable INT0 interrupt
.....
.....
}//end of main loop

disabling the INT0 for few seconds allow the time to the motor to release the limit switch because this motor has unpredictable direction of rotation... then the INT0 is re-enabled waiting for the limit switch to be hitted and the ISR to be excuted as INT0 pin becomes Low:
ISR(INT0_vect){
  digitalWrite(MOTOR_PIN, LOW);
  GICR &= 0xBF;  //disable INT0 interrupt
}

the INT0 is disabled to allow the next cycle of the motor after one hour...
the problem is that the motor stops sometimes in the middle before hitting the limit switch and sometimes it continue turning after hitting the limit switch... and the majority of times it work as expected...
I do not understand the reason for this behavior... and what are the elements to check...
EDIT: the full code
#define LIMIT_SWITCH     2       // pd2 (INT0)
#define HEATER_PIN      29       // pc7
#define MOTOR_PIN       27       // pc5

#define  ONE_HOUR (1*60*60*1000)

Si7021 sensor = Si7021();

unsigned long lastT;

float tmp , Setpoint;

void setup()
{
  Serial.begin(9600);
  Setpoint = 37;
  lastT = millis();
  pinMode(MOTOR_PIN, OUTPUT);
  pinMode(LIMIT_SWITCH, INPUT_PULLUP);
  GICR|=0x40;                        // enable INT0 interrupt
  MCUCR=0;
}

ISR(INT0_vect){
  digitalWrite(MOTOR_PIN, LOW);
  GICR &= 0xBF;                      // disable INT0 interrupt
}

void loop()
{
  tmp = sensor.readTemperature();
  if(tmp>Setpoint + 0.5) digitalWrite(HEATER_PIN, LOW);
  if(tmp<Setpoint - 0.5) digitalWrite(HEATER_PIN, HIGH);
  Serial.println(tmp);

  if((millis() - lastT)>=ONE_HOUR) {
    GICR &= 0xBF;                    // disable INT0 interrupt
    digitalWrite(MOTOR_PIN, HIGH);
    lastT = millis();
  }

  delay(5000);                       // time for motor to quit the limit switch
  GICR |= 0x40;                      // enable INT0 interrupt
}

A race condition? Please post a Minimal, Complete, and Verifiable example

How is the direction of the motor unpredictable?

@chrisl: excuse my late response... it's a microwave turntable ac motor... unpredictable means that it starts turning in a random direction...

I think that the issue comes from the internal pull-up resistor wich i think is insufficient... I connect a 5.5kOhm resistor between INT0 pin and Vcc and until this time everything is OK...


text:
DigiKeyboard BIOS Compatibility
I am using a custom version of the DigiKeyboard library, to use a Digispark as a keyboard in the BIOS. It works on most computers, but HP 730 Thin clients dont recognize it as a keyboard.
Below is the custom version. Any suggestions on how to fix this issue? Thank you in advance for any suggestions/help.
/*
 * Based on Obdev's AVRUSB code and under the same license.
 *
 * TODO: Make a proper file header. :-)
 * Modified for Digispark by Digistump
 */
#ifndef __DigiKeyboard_h__
#define __DigiKeyboard_h__

#include <Arduino.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <string.h>

#include "usbdrv.h"
#include "scancode-ascii-table.h"

// TODO: Work around Arduino 12 issues better.
//#include <WConstants.h>
//#undef int()

typedef uint8_t byte;

#define BUFFER_SIZE 2 // Minimum of 2: 1 for modifiers + 1 for keystroke

static uchar    idleRate;           // in 4 ms units

/* Boot protocols have been added.
 * We do allow simultaneous key presses.
 * The report descriptor has been created with usb.org's "HID Descriptor Tool"
 * which can be downloaded from http://www.usb.org/developers/hidpage/.
 * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
 * for the second INPUT item.
 */
const PROGMEM uchar usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
        0x05, 0x01, // USAGE_PAGE (Generic Desktop)
        0x09, 0x06, // USAGE (Keyboard)
        0xa1, 0x01, // COLLECTION (Application)
        0x05, 0x07, // USAGE_PAGE (Keyboard)
        0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
        0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
        0x15, 0x00, // LOGICAL_MINIMUM (0)
        0x25, 0x01, // LOGICAL_MAXIMUM (1)
        0x75, 0x01, // REPORT_SIZE (1)
        0x95, 0x08, // REPORT_COUNT (8)
        0x81, 0x02, // INPUT (Data,Var,Abs)
        0x95, 0x01, // REPORT_COUNT (1)
        0x75, 0x08, // REPORT_SIZE (8)
        0x81, 0x03, // INPUT (Cnst,Var,Abs)
        0x95, 0x05, // REPORT_COUNT (5)
        0x75, 0x01, // REPORT_SIZE (1)
        0x05, 0x08, // USAGE_PAGE (LEDs)
        0x19, 0x01, // USAGE_MINIMUM (Num Lock)
        0x29, 0x05, // USAGE_MAXIMUM (Kana)
        0x91, 0x02, // OUTPUT (Data,Var,Abs)
        0x95, 0x01, // REPORT_COUNT (1)
        0x75, 0x03, // REPORT_SIZE (3)
        0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
        0x95, 0x06, // REPORT_COUNT (6)
        0x75, 0x08, // REPORT_SIZE (8)
        0x15, 0x00, // LOGICAL_MINIMUM (0)
        0x25, 0x65, // LOGICAL_MAXIMUM (101)
        0x05, 0x07, // USAGE_PAGE (Keyboard)
        0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
        0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
        0x81, 0x00, // INPUT (Data,Ary,Abs)
        0xc0 // END_COLLECTION
};

/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
 * 10 Keyboard/Keypad Page for more codes.
 */
#define MOD_CONTROL_LEFT    (1<<0)
#define MOD_SHIFT_LEFT      (1<<1)
#define MOD_ALT_LEFT        (1<<2)
#define MOD_GUI_LEFT        (1<<3)
#define MOD_CONTROL_RIGHT   (1<<4)
#define MOD_SHIFT_RIGHT     (1<<5)
#define MOD_ALT_RIGHT       (1<<6)
#define MOD_GUI_RIGHT       (1<<7)

#define KEY_A       4
#define KEY_B       5
#define KEY_C       6
#define KEY_D       7
#define KEY_E       8
#define KEY_F       9
#define KEY_G       10
#define KEY_H       11
#define KEY_I       12
#define KEY_J       13
#define KEY_K       14
#define KEY_L       15
#define KEY_M       16
#define KEY_N       17
#define KEY_O       18
#define KEY_P       19
#define KEY_Q       20
#define KEY_R       21
#define KEY_S       22
#define KEY_T       23
#define KEY_U       24
#define KEY_V       25
#define KEY_W       26
#define KEY_X       27
#define KEY_Y       28
#define KEY_Z       29
#define KEY_1       30
#define KEY_2       31
#define KEY_3       32
#define KEY_4       33
#define KEY_5       34
#define KEY_6       35
#define KEY_7       36
#define KEY_8       37
#define KEY_9       38
#define KEY_0       39

#define KEY_ENTER   40

#define KEY_SPACE   44

#define KEY_F1      58
#define KEY_F2      59
#define KEY_F3      60
#define KEY_F4      61
#define KEY_F5      62
#define KEY_F6      63
#define KEY_F7      64
#define KEY_F8      65
#define KEY_F9      66
#define KEY_F10     67
#define KEY_F11     68
#define KEY_F12     69

#define KEY_LEFT        0x50
#define KEY_RIGHT     0x4F
#define KEY_DOWN        0x51
#define KEY_UP          0x52
#define KEY_DEL         0x4C
#define KEY_TAB       0x2B
#define KEY_BACKSP    0x2A
#define KEY_TILDE     0x35
#define KEY_MINUS     0x2D
#define KEY_EQUAL     0x2E
#define KEY_L_BRACE   0x2F
#define KEY_R_BRACE   0x30
#define KEY_BACKSLASH 0x31
#define KEY_SEMICOLON 0x33
#define KEY_QUOTE     0x34
#define KEY_COMMA     0x36
#define KEY_PERIOD    0x37
#define KEY_SLASH     0x38

#define KEY_ESC       0x29

class DigiKeyboardDevice : public Print {
 public:
  DigiKeyboardDevice () {
    cli();
    usbDeviceDisconnect();
    _delay_ms(250);
    usbDeviceConnect();

    usbInit();

    sei();

    // TODO: Remove the next two lines once we fix
    //       missing first keystroke bug properly.
    memset(reportBuffer, 0, sizeof(reportBuffer));
    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
  }

  void update() {
    usbPoll();
  }

    // delay while updating until we are finished delaying
    void delay(long milli) {
        unsigned long last = millis();
      while (milli > 0) {
        unsigned long now = millis();
        milli -= now - last;
        last = now;
        update();
      }
    }

  //sendKeyStroke: sends a key press AND release
  void sendKeyStroke(byte keyStroke) {
    sendKeyStroke(keyStroke, 0);
  }

  //sendKeyStroke: sends a key press AND release with modifiers
  void sendKeyStroke(byte keyStroke, byte modifiers) {
    sendKeyPress(keyStroke, modifiers);
  delay(10);
    // This stops endlessly repeating keystrokes:
    sendKeyPress(0,0);
  }

  //sendKeyPress: sends a key press only - no release
  //to release the key, send again with keyPress=0
  void sendKeyPress(byte keyPress) {
    sendKeyPress(keyPress, 0);
  }

  //sendKeyPress: sends a key press only, with modifiers - no release
  //to release the key, send again with keyPress=0
  void sendKeyPress(byte keyPress, byte modifiers) {
    while (!usbInterruptIsReady()) {
      // Note: We wait until we can send keyPress
      //       so we know the previous keyPress was
      //       sent.
        usbPoll();
        _delay_ms(5);
    }

    memset(reportBuffer, 0, sizeof(reportBuffer));

    reportBuffer[0] = modifiers;
    reportBuffer[3] = keyPress;

    usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
  }

  size_t write(uint8_t chr) {
    uint8_t data = pgm_read_byte_near(ascii_to_scan_code_table + (chr - 8));
    sendKeyStroke(data & 0b01111111, data >> 7 ? MOD_SHIFT_RIGHT : 0);
    return 1;
  }

  //private: TODO: Make friend?
  uchar    reportBuffer[8];    // buffer for HID reports [ 1 modifier byte + (len-1) key strokes]
  using Print::write;
};

DigiKeyboardDevice DigiKeyboard = DigiKeyboardDevice();

#ifdef __cplusplus
extern "C"{
#endif
  // USB_PUBLIC uchar usbFunctionSetup
    uchar usbFunctionSetup(uchar data[8]) {
    usbRequest_t    *rq = (usbRequest_t *)((void *)data);

    usbMsgPtr = DigiKeyboard.reportBuffer; //
    if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
      /* class request type */

      if (rq->bRequest == USBRQ_HID_GET_REPORT) {
                /* wValue: ReportType (highbyte), ReportID (lowbyte) */

                /* we only have one report type, so don't look at wValue */
        // TODO: Ensure it's okay not to return anything here?
                return 0;

      } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
                //usbMsgPtr = &idleRate;
                //return 1;
                return 0;

      } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
                idleRate = rq->wValue.bytes[1];

      }
    } else {
      /* no vendor specific requests implemented */
    }

    return 0;
  }
#ifdef __cplusplus
} // extern "C"
#endif

#endif // __DigiKeyboard_h__

Welcome to SE/Arduino! Please take the [tour] to learn how this site works, and read "[ask]". Then come back and [edit] your question to clarify. -- Do you have access to a USB analyzer/sniffer? If so, please tap the USB connection and watch the enumeration process and what follows. -- Did you search for information of the HP's requirements for keyboards, what did you find, and why does it not help you? -- Do you have another USB keyboard that works? If so, you might want to connect it to a Linux computer and look into the system logs for difference between that and your DigiKeyboard.

Thank you for your response. In asking what I tried, you answered my question of what I can try. Didn't know USB analyzer/sniffers existed. And the idea of checking it against a known good keyboard in linux is great. Thank you for your help!

Thanks for the flowers! However, these are just the next steps without guarantee of progress, but might help to finally find the solution. If you do, please come back and write an actual answer, marking it (later) as accepted.

"a custom version of the DigiKeyboard library" is likely part of the problem based on what I see.  But confirmation is in what I don't see. Where is the rest of the code?


text:
Arduino IDE and subfolders
I have a sketch with multiple source files and folders arranged like so. I've divided up the project like this to keep things clean.
|
\---project
    |   project.ino
    |   types.h
    |
    +---sub1
    |       gadget1.c
    |       gadget1.h
    |       gadget2.c
    |       gadget2.h
    |
    \---blarg
            foobar.c
            foobar.h

The sketch file includes the headers via quoted include directives (rather than the lib alternative with angled brackets). This seems to work for compilation.
However, when the IDE tries to link, all references to implementations (c source files) in the subfolders generate "undefined reference" errors. Almost as if the IDE is completely ignoring the C source files.
In trying to resolve this I've discovered that apparently the handling of subfolders by the IDE seems to be all over the place. Some versions only acknowledge headers in subfolders, others work if you put everything in a "src" folder (I've also seen mention of a "utility" folder), some people suggest modifying environment variables, etc. I've even tried manually adding source files via the "sketch/add file" option which makes the files visible in the IDE but does not solve the linking problems. All these methods seem to depend on IDE version, and I couldn't distill what was the correct way vs a hack or work-around.
So my question is what is the correct/current way of organizing the above project so that it can be compiled/linked using the IDE? I am using IDE version 1.8.5 which I believe is either the latest version, or close too it.

src and util are used in library folder structure, not for project folder. 1.8.5 is current release version

I find it humorous that the other two people responding are authors of alternative IDE projects and likely don't even use the Arduino IDE. So of course they are providing erroneous information.

sorry Per. I use Sloeber, but I am not the author :-). I knew that you will write the right answer. Majenko deleted his answer

From Arduino IDE 1.6.10 onward the Arduino IDE compiles all source files in the src subfolder of the sketch and recursively through all folders under the src folder.
Support for compilation of sketch subfolders was added one or two IDE versions before 1.6.10 and was originally not limited to the src folder but a lot of problems were reported by people who had stored separate programs in subfolders of their sketch that caused compilation errors so this feature was restricted to the src subfolder only.
So if you structure a sketch like this:
foo
|_foo.ino
|_src
   |_bar.cpp
   |_bar.h

And use this #include directive in your sketch:
#include "src/bar.h"

it will work fine.

Almost as if the IDE is completely ignoring the C source files.

Arduino sketches are converted to C++ before being compiled. They are not C. If you want to use C in C++ code you need to wrap it in extern "C" {}
extern "C" {
#include "src/sub1/gadget1.h"
}

what is the correct/current way of organizing the above project

project
|_project.ino
|_types.h
|_src
   |_sub1
   |  |_gadget1.c
   |  |_gadget1.h
   |  |_gadget2.c
   |  |_gadget2.h
   |_blarg
      |_foobar.c
      |_foobar.h

not working with 1.8.12. any constellation gives me: bash: line 0: [: too many arguments cp: target 'partitions.csv' is not a directory exit status 1


text:
change sketch from controlling 8 stepper motors to 8 solenoids
I am looking to see if I can change the attached sketch which controls 8 stepper motors to just switching 8 relays for a weaving loom which we have, unfortunately making this change is well above my paygrade lol. I am using an arduino mega and 8 channel relay board which will in turn trip the solenoids which the loom already has attached, thanks for any help
This is the Sketch im trying to alter

// Loom interface for Ashford Dobby interface (using 8 stepper motors):
// Arduino lines 0 & 1 to USB interface
// line 13 Is foot pedal
// 14-43 are motor controls

// General definitions:
#define MAX_CHARS 80
#define DEBUG 0
#define MOTORS 8
#define IDENTITY "Generic Dobby Interface (Jones Stepper Motor Dobby)\n"

// Data controlling motor positions, states, etc:
const long MOTOR_DELAY=900;                                                      // Time delay between motor steps (reduce till shafts move reliably)
const long  SHAFT_UP=8*170, SHAFT_DOWN=0 ;                                       // Number of motor steps required to raise the shafts
unsigned long shaft_state=0x00000000, shaft_cue=0xffffffff;                      // tracking current & next desired states of shaft controls
long MotorActual[MOTORS], MotorWant[MOTORS];                                     // Current & desired position for each of the motors

// Definition of which Output pins connect to which motor
char MotorPin[MOTORS][4]=                                                        // Motors 1,3,5,7 on right, 2,4,6,8 on left: left side reverses direcion
              { {14,15,16,17}, {18,21,20,19}, {22,23,24,25}, {26,29,28,27},      // Motors 1-4
                {30,31,32,33}, {34,37,36,35}, {38,39,40,41}, {42,45,44,43}};     // Motors 5-8

unsigned long NextMotorUpdate=0;                                                 // Timer for when next motor step occurs
const int ADVANCE  =13;                                                          // input pin for footswitch (has pullup, switch contact only)

// Serial (USB) interface
// Serial interface is a "Generic" dobby interface:
// Host sends which shafts should be activated for current shot
// Shafts will raise when the foot switch is activated
// Shafts return when foot switch is released, and the "Advance" command returned to host
// Also responds to "?" with the "IDENTITY" identified above, shows host who's out here

int serial_chars=0;                                                              // Number of characters in the serial input buffer
char serial_string[MAX_CHARS]="";                                                // Serial input buffer
char Message[MAX_CHARS]="";                                                      // Output message buffer
long serial_time=0;                                                              // Used to close serial string on timeout (timer)
const int serial_timeout=100;                                                    // Digest Serial string after timeout
char serial_idle=1;                                                              // Tracks activity on the serial bus
char HostPresent = 1;                                                            // set when some host is identified
int Button_state=1;                                                              // tracks changes in floor-switch state

////////////////////////////////////////////////////////////////////////
// Send shaft controls to hardware
////////////////////////////////////////////////////////////////////////
    void set_motor(char m,char state)                                            // Lowest level function to handle step in motors
    {
//   sprintf(Message,"M %d @ state %d\n",m,state);
//   Serial.write(Message);
     switch(state)
     {
      case 0:                                                                    // Set motor inactive
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 1:                                                                    // Set motor State 1
      digitalWrite(MotorPin[m][0], 1);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 2:                                                                    // Set motor state 2
      digitalWrite(MotorPin[m][0], 1);    digitalWrite(MotorPin[m][1], 1);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 3:                                                                    // Set motor state 3
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 1);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 4:                                                                    // Set motor state 4
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 1);
      digitalWrite(MotorPin[m][2], 1);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 5:                                                                    // Set motor state 5
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 1);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 6:                                                                    // Set motor state 6
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 1);    digitalWrite(MotorPin[m][3], 1);
      break;

      case 7:                                                                    // Set motor state 7
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 1);
      break;

      case 8:                                                                    // Set motor state 8
      digitalWrite(MotorPin[m][0], 1);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 1);
      break;
     }
    }

   char set_motors()                                                            // Set all motors to new motor state - called for each motor step on any motor
    {                                                                            // return indicates if any motor is still active
     int m=0;
     long setting, entry_setting;
     char active=0;

     while(m<MOTORS)
     {
                                                                                // Check for necessary directional movement
      entry_setting=setting=MotorActual[m];
      if(setting==MotorWant[m])       setting=setting;
      else if(setting<MotorWant[m])   setting++;
      else                            setting--;
                                                                                // Send update setting controls
      if((entry_setting!=MotorWant[m]))
      {
       active=1;
       MotorActual[m]=setting;                                                   // update actual for move in progress
       setting=(setting&7)+1;                                                    // set_motor state 0 is inactive, 1-8 are active
       set_motor(m,setting);                                                     // Set new motor state
      }
      m++;                                                                       // Next motor
     }
     if(active==0)
     {                                                                           // If done kill power to the motors that are back in passive state
      m=0;
      while(m<MOTORS)
      {
       if(MotorActual[m]==SHAFT_DOWN)set_motor(m,0);                             // set motor inactive
       m++;
      }
     }
     return active;
    }

    char run_motors()                                                            // Higher level function to set motors to desired positions
    {                                                                            // return indicates if motors are active or idle
     char active=1;
     if(micros()>=NextMotorUpdate)
     {                                                                           // time to update the motor positions
      active=set_motors();                                                       // Update all motors
      NextMotorUpdate=micros()+MOTOR_DELAY;                                      // set clock for next update
     }
     return active;
    }

    void set_shafts(unsigned long shafts)                                        // Called to set desired motor positions based on which shafts were requested
    {                                                                            // This assumes all shafts move the same amount, they really don't need to
     unsigned long bit_mask=1;
     int i=0;
     while(i<MOTORS)
     {
      if(shafts&bit_mask)MotorWant[i]=SHAFT_UP;
      else               MotorWant[i]=SHAFT_DOWN;
//    sprintf(Message,"M %d @ want %d\n",i,MotorWant[i]>>8);
//    Serial.write(Message);
      i++;
      bit_mask=bit_mask<<1;
     }
    }
////////////////////////////////////////////////////////////////////////
// Preset- Called on initialization
////////////////////////////////////////////////////////////////////////
    void preset()                                                                // Could raise all shafts to show it's working, etc.
    {                                                                            // This version doesn't do anything, default will lift all shafts when the foot switch is pressed before anything else is requested
    }

//////////////////////////////////////////////////
// SERIAL INTERFACE (USB) FUNCTIONS
//////////////////////////////////////////////////
                                                                                // USB input commands:
                                                                                // 1,2,3,n            Set shafts 1,2,3,n
                                                                                // ?                  ID request, respond with ID
    unsigned long get_shafts(char* command)                                      // Input is series of numbers, comma seperated, for shafts to raise
    {                                                                            // returns word indicating which shafts were identified in string
     int chars=strlen(command);                                                  // Number of characters in input string
     int i=0;
     unsigned long shafts=0, bits;                                               // Sets bits for shafts indicated
     char shaft=0, digit=0, character;

     while(i<=chars)                                                             // loop through all characters in command
     {
      character=command[i];

      if((character==',')||(i==chars))
      {                                                                          // have field seperator or end of string, not shaft desired
       if((shaft>0)&&(shaft<=32))
       {                                                                         // 'shafts' notes this shaft is required
        bits=1<<shaft-1;
        shafts|=bits;
        shaft=0;
       }
      }
      else if(('0'<=character)&&(character<='9'))
      {                                                                          // have digit
       character&=0x0f;                                                          // reduce to decimal
       shaft=shaft*10+character;
      }
      else if((character==' ')||(character=='\n'));                              // ignore spaces/returns
      else
      {
       Serial.println("Invalid Character detected in command:");                 // debug display of command extracted
       Serial.println(command);                                                  // debug display of command extracted
       i=chars;                                                                  // quit, got crap
      }
      i++;
     }
     return shafts;
    }

    void digest_serial(char* command)                                            // Main serial response function
    {
     int chars=strlen(command);                                                  // Number of characters in command

     if(chars>0)
     {                                                                           // If something to do go digest the input
      HostPresent=1;                                                             // note that there's something out there talking to me
      if(('0'<=command[0])&&(command[0]<='9'))                                   // go number, should be shafts
       shaft_cue=get_shafts(command);                                            // convert ASCII string to binary word
      else  if((command[0]=='c')||(command[0]=='t'))                             // test command to cycle valves
       preset();                                                                 // cycle through the valves (nothing defined for this loom, could implement shaft self test, etc)
      else if(command[0]=='?')
      {                                                                          // Have a "Who are You?" kind of command, tell host who we are
       char message[256]=IDENTITY;                                               // Build primary Identity command
       message[strlen(message)-1]=0;                                             // delete return in line
       sprintf(message,"%s  [Solenoid state = 0x%3x]\n",message,shaft_state);    // note what we'll do when button is pressed
       Serial.write(message);                                                    // Send identity with current switch state to host (for troubleshooting)
      }
     }
    }

    void serial_input()
    {                                                                            // High level Serial processing
     char inChar;
     char command[MAX_CHARS]="";

     while((Serial.available()>0))
     {                                                                           // Get serial command from host (character by character)
      inChar=char(Serial.read());
      serial_string[serial_chars]=inChar;
      serial_chars++;
      serial_string[serial_chars]=0;
      serial_time=millis();
     }
     if((serial_chars>0)&&(serial_idle)&&((serial_string[serial_chars-1]=='\n')||(millis()>(serial_time+serial_timeout))))
     {                                                                           // If have a command, go digest it
      serial_idle=0;
      strcpy(command,serial_string);
      serial_chars=0;
      serial_string[0]=0;
//    Serial.println(command);                                                   // debug display of command extracted
      digest_serial(command);
                                                                                // done with last command, clear the input buffers
      serial_idle=1;                                                             // ready for more serial input
     }
    }

////////////////////////////////////////////////////////////// /
// Foot Switch monitor  - set shafts/tell host to advance
////////////////////////////////////////////////////////////// /
    void monitor_button()
    {                                                                            // check for button push to advance, sent only when button pushed (not held)
     char state=digitalRead(ADVANCE);                                            // read state of foot switch (0=active, 1=inactive)

     if(state==0)
     {                                                                           // button is pressed,
      set_shafts(shaft_cue);                                                     // Set motor desired states from the list of shafts desired for this shot
      run_motors();                                                              // Go run the motors to make it happen
     }
     else
     {                                                                           // button is not pressed,
      set_shafts(0);                                                             // Set motor desired states back to reset condition
      run_motors();                                                              // Make it happen
      if(Button_state!=state)
       Serial.write("ADVANCE\n");                                                // Send "Advance" when foot switch is released
     }
     if(state!=Button_state)                                                     // Check if button has changed state
      delay(500);                                                                // Wait half a second on changes to debounce switch
     Button_state=state;                                                         // Track current state of the button to look for changes
    }

//////////////////////////////////////////////////
// TOP LEVEL FUNCTIONS - SETUP & LOOP                                                                                //
//////////////////////////////////////////////////
    void setup()
    {
     char m;                                                                     // Motor indicator

                                                                                // USB Interface to host computer
     Serial.begin(9600);                                                         // start serial port at 9600 bps:
     Serial.print(IDENTITY);                                                     // print message on serial monitor

                                                                                // Motor Controls
                                                                                // set motor controls for all motors
     m=0;
     while(m<MOTORS)
     {
      digitalWrite(MotorPin[m][0], LOW);                                         // set low
      digitalWrite(MotorPin[m][1], LOW);                                         // set low
      digitalWrite(MotorPin[m][2], LOW);                                         // set low
      digitalWrite(MotorPin[m][3], LOW);                                         // set low
      pinMode(MotorPin[m][0], OUTPUT);                                           // Set as output bit
      pinMode(MotorPin[m][2], OUTPUT);                                           // Jumble order to keep motor from moving
      pinMode(MotorPin[m][1], OUTPUT);                                           // Set as output bit
      pinMode(MotorPin[m][3], OUTPUT);                                           // Set as output bit
      MotorWant[m]=MotorActual[m]=0;                                             //
      m++;
     }

      pinMode(ADVANCE, INPUT_PULLUP);                                            // Set as input pin to handle the foot switch
      preset();                                                                  // "self test" - note it's alive
      unsigned long T0=millis();                                                 // Note start up time
     }

    void loop()
    {
     serial_input();                                                             // check the serial interface, handle if it comes in
     monitor_button();                                                           // check for button push
    }

it's not possible to do what you want without knowing how the solenoid action replaces the motor action ... basically, what the motors do, at what time do they do it, and how do the solenoids replace the function that the motors do

comments are not part of the code ... they should not be interweaved into the code ... cleaned up the program listing for you

Hi Jsotola, thankyou for your reply, all the solenoid will do is activate when the motor would normally, ie instead of the motor engaging and doing x number of rotations the solenoid will just engage, this is triggered by the software that is running on windows to create and run a pr determined pattern, then when the foot switch is triggered the solenoid will disengage and the pc software will move to the next step in the pattern and engage the correct solenoids. sorry about all of the comments as these were already in the sketch that I found.

lots of comments are a very good thing, but they should not clutter the code ... that's all I'm saying

I always thought the best place for comments are at the beginning of the functions. Good comments there indicate thought went into segmenting the task into nicely organized functions. However, even the giants like NXP and STMicro do not regularly do this in their code. Also, comments like "Set motor State 1" are worthless. Seasoned programmers will instantly comment: "That's obvious ... but what is 'State 1' ... that's the real question / comment to be made."

The assumed goal is to automate a Weaving Loom using solenoids instead of steppers.

This video claims a 3kg pull is necessary. It may be difficult to find an appropriate / economical solenoid with that kind of pull, stroke distance & rated for continuous duty (hold its position for a prolonged period of time without harming its self from heat related problems).

If sourcing such a solenoid is not a problem, there are only 2 functions in the above code that control the steppers. "set_motor" and "setup". Change those to activate / deactivate solenoids.

Also, this might be harder, remove the code that cycles the steppers into / out-of position. You don't need that w/the solenoids.

I would first figure out what each stepper motor code segment is doing, in overview. Think of viewing the process while standing back from it and describe the reason that code segment is there, more than what, specifically, it does - what it's relationship is to the process, not to the motor.
Move those motor segments into functions, and put function calls where the motor segments used to be.
Now replace the motor code inside each function with solenoid code. This is why we wanted an abstract overview of those motor segments. In each function, you'll write solenoid-specific code that has that same relationship to the overall process as the motor code did, but you'll tailor the specifics to the solenoids.