Detecting position on round disc using SG-2BC ir sensor

Currently I'm testing how to detect position on a round disc, using only a SG-2BC IR reflection sensor.

The disc has 25 holes on the same radius in the same distance. but between hole 24 and hole 0 there is an additional hole.


I'm using an SG-2BC sensor, which is quite difficult to use, as I'm getting random values.

I need to enable the IR tx part by settign D46 to HIGH.
Then I should be able to read a proper value of my analog pin A4.
But the value is terribly swinging.
Do I have to add a capacitor on my A4 pin to stabilize the value while reading?

And I'm also not sure how to measure how many steps a whole rotation of my disc needs (must be nearly 12000 steps per position => 25*12000=300000 steps per revolution) or how to detect my unique marker.
As all 25 holes have the same distance, but the stop marker is in between marker 24 and 0, I'm thinking of using an array to store all the steps where a hole begins and ends.
But when entering a hole, I get alternating values (I testet this slowly by turning an LED on and off depending if I can detect a hole or not).

So where would you guys start?
Do I have to add en impedance converter close to my sensor or will a capacitor (which value? on my A4 pin work?

The disc is driven by an TMC2130 (non-SPI mode).

Any help appreciated!

You have a reflective sensor.
What do you want to do reflect of the surface between the holes or the holes.
Do you have a reflective surface on the other side to reflect the IR back?

A complete readable schematic would be good and the code your are using?
I hope you have some simple code that just reads the sensor and not a full code with code for other hardware that you may have connected.

What is the application?
What is the speed of the disk, frequency of the hole detections.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

How do you drive the disc?

I don't have a code yet, as I don't know where to start.
As soon as I'm using the serial monitor the values start getting crazy. I've run the disc (I guess one revolution needs 40-60 seonds) and an LED showed properly wether the sensor detects a hole or not.
But as soon as I'm reading the analog value, everything slows down extremly.
As soon as I start using serial connection to analyze in realtime everything becomes crazy (values between 20-800 while the disc is not rotating).
The material of the disc is transparent acryl. So while the sensor is above the disc, the IR light is reflected and I usually get values smaller than 500. When the sensor is above a hole, the value is greater than 500.

Why can't I read out the analog value using serial monitor?
I thought it would be a problem with my schematics - so I just re-build the basic thing using an old Ramps 1.3 board from my 3d printer (which I replaced by Ramps 1.4...).
Just connected the TMC2130 stepperdriver as well as the IR sensor.
IRtx means the IR diode in the sensor.
IRrx is the photo-transisor.

Using a smaller value then 10Megs the sensor didn't work.

As I cannot read out analog values and transmit them using the serial connection, I need to connect an LED, again, to see wether the value is high or low.

// 0,7V Vref TMC2130

#include <TMC2130Stepper.h>

#define EN_PIN    38
#define DIR_PIN   55
#define STEP_PIN  54

int sensorValue = 0;
const int IRrx = A4;
const int IRtx = 48;

void setup() {
  while (!Serial) {;}

	pinMode(EN_PIN, OUTPUT);
	pinMode(DIR_PIN, OUTPUT);
	digitalWrite(EN_PIN, LOW);		// HIGH to disable

	pinMode(IRtx, OUTPUT);
	digitalWrite(IRtx, HIGH);
	pinMode(IRrx, INPUT);

void loop() {
	sensorValue = analogRead(IRrx);

	digitalWrite(DIR_PIN, HIGH);
	digitalWrite(STEP_PIN, HIGH);
	digitalWrite(STEP_PIN, LOW);


07:27:00.747 -> sensor = 177
07:27:01.493 -> sensor = 480
07:27:02.240 -> sensor = 707
07:27:03.029 -> sensor = 584
07:27:03.770 -> sensor = 303
07:27:04.517 -> sensor = 127
07:27:05.263 -> sensor = 341
07:27:06.051 -> sensor = 651
07:27:06.796 -> sensor = 668
07:27:07.541 -> sensor = 390
07:27:08.332 -> sensor = 126
07:27:09.071 -> sensor = 259
07:27:09.818 -> sensor = 595
07:27:10.560 -> sensor = 700
07:27:11.347 -> sensor = 450
07:27:12.094 -> sensor = 162
07:27:12.834 -> sensor = 213
07:27:13.624 -> sensor = 547
07:27:14.364 -> sensor = 711
07:27:15.108 -> sensor = 496
07:27:15.890 -> sensor = 195
07:27:16.630 -> sensor = 190
07:27:17.371 -> sensor = 507

Your sensor reads REFLECTED IR, the IR is possibly reflecting of the disk between the holes.
Can I suggest you use one of these, its called a "photo-interrupter"


photo interrupter arduino tutorial

You will see how it will be ideal for your project to detect the holes.
Thanks.. Tom... :smiley: :+1: :coffee: :australia:

To best look at the sensor response, you would be better to use the IDE plotter;

If you keep the hole opposite the sensor what do you get?
If you keep the space between the hole opposite the sensor what do you get?

Tom.. :smiley: :+1: :coffee: :australia:

I can't change the sensor anymore. The parts of the rotary have been machined and it would be too expensive and there's no time to start from zero :frowning:

Using this code the backlight of my LCD showed properly if the sensor is above a hole or above the disc:

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#include <TMC2130Stepper.h>

//int stepdelay = 5;
int stepdelay = 14;		// time between steps - defines speed max
int StepDuration = 10;	// time high level is held to transmit signal properly

int ButtonUp     = 37;              // input buttons
int ButtonDown   = 40;
int ButtonLeft   = 36;
int ButtonRight  = 35;
int ButtonSelect = 19;

unsigned long testSteps = 302450*10;	// fast genau 1512000*2   // als: 302400

int VccLOAD = 22;			// enables power for fan and stepper motor
int pwrSens12V = A0;			// check is 12V is present. Voltagedevider on 12V
int pwr12value = 0;
int USBpwr = A7;			// if high USB-PWR! Don't power up VccLOAD
#define EN_PIN    10  // Nano v3:	16 Mega:	38	//enable (CFG6)
#define DIR_PIN   7  //			19			55	//direction
#define STEP_PIN  6  //			18			54	//step

const int TMC_CF0 = 5;		// TMC2130 CFG0, non-SPI-mode only
const int TMC_CF1 = 3;		// TMC2130 CFG1, non-SPI-mode only
const int TMC_CF2 = 2;		// TMC2130 CFG2, non-SPI-mode only
const int TMC_CF3 = 31;		// CS (SPI) / CFG3

const int IRrx = A4;
const int IRtx = 46;
const int positionSensor = A7;

int sensorValue = 0;
int sensorValue2 = 0;

void setup() {
	pinMode(VccLOAD, OUTPUT);
	pinMode(DIR_PIN, OUTPUT);
	pinMode(EN_PIN, OUTPUT);
	pinMode(TMC_CF0, OUTPUT);
	pinMode(TMC_CF1, OUTPUT);
	pinMode(TMC_CF2, OUTPUT);
	pinMode(USBpwr, INPUT);
	pinMode(pwrSens12V, INPUT);
	pinMode(ButtonUp, INPUT_PULLUP);
	pinMode(ButtonDown, INPUT_PULLUP);
	pinMode(ButtonLeft, INPUT_PULLUP);
	pinMode(ButtonRight, INPUT_PULLUP);
	pinMode(ButtonSelect, INPUT_PULLUP);
	pinMode(IRtx, OUTPUT);
	pinMode(IRrx, INPUT);
	digitalWrite(IRtx, HIGH);
	// see: -> TMC2130 Standalone Modus (only VIO=HIGH and GND=LOW available)
	digitalWrite(TMC_CF0, LOW);	// Chopper Off Time TOFF (GND=140tclk, VIO=236tclk, OPEN=332tclk)
	digitalWrite(TMC_CF1, HIGH);	// see: Schrittkonfiguration
	digitalWrite(TMC_CF2, HIGH);	// see: Schrittkonfiguration 
	digitalWrite(EN_PIN, HIGH);		// HIGH to disable

	// turn loadPWR on
	if (digitalRead(USBpwr) == LOW){
	digitalWrite(VccLOAD, HIGH);
	lcd.print("load on!");
	// check if 12V is present. A value of 800-900 means 12V is present.
	// only works on 12V DC! (on USB-pwr analogRead seems to freeze)
	pwr12value = analogRead(pwrSens12V);

	// turn TMC2130 on
	if (pwr12value >= 750) {digitalWrite(EN_PIN, HIGH);}		// low to enable, only if 12V is present!
	lcd.print("TMC2130 on = LOW");

	else {
		lcd.print("USB PWR!");

	lcd.print(" steps");

void loop() {
	while (digitalRead(ButtonUp) == LOW){
			if (testSteps<= 40000000){
			testSteps +=100;
	while (digitalRead(ButtonDown) == LOW){
			if (testSteps>= 1000){
			testSteps -=100;

	while (digitalRead(ButtonLeft) == LOW){
			StepperImperator (testSteps, 1);
			//StepperImperator (testSteps, 1);
	while (digitalRead(ButtonRight) == LOW){
			StepperImperator (testSteps, 0);
			//StepperImperator (testSteps, 0);


void StepperImperator(long steps, int dir){
	digitalWrite(EN_PIN, LOW);	//enable stepper driver
	if (dir == 1){
		digitalWrite(DIR_PIN, HIGH);
	else {digitalWrite(DIR_PIN, LOW);}
	for (int i=0; i<steps; i++){
		digitalWrite(STEP_PIN, HIGH);
		digitalWrite(STEP_PIN, LOW);

		// Sensor
		if (i%100 == 0){
			if (digitalRead(IRrx) == 0){
			else {
	digitalWrite(EN_PIN, HIGH);	//disable stepper driver

So in general the sensor works fine with the acrylic disc.

But as I just build a basic setup using the Ramps board and the sensor only, I'd like to program the position detection, first.
Creating the code around the position-thing is just a matter of time and it won't be a problem for me.

This plot is created while there is no movement.

Here's a video of the detection:

That plot looks like you are picking up mains or some other interference if your target is a constant reflectivity.

Can you please post a circuit diagram so we can see your component layout?

Have you tried using digitalRead instead of analogRead, the output of the sensor looks like it goes HIGH and LOW enough in input to be interpreted as a digital signal.

Was there any particular reason for t he sensor you chose?
Photo-interrupters are use in printers and other speed position detecting setups.

What is the application?
Did you try other sensors before going to hardware design and manufacture?

Tom... :smiley: :+1: :coffee: :australia:

I would say your biggest problem is you are using a reflective sensor and not a transmitter and receive sensor that would let you detect the hole precisely.

Tom.. :smiley: :+1: :coffee: :australia:

Looks like you have 10 meg for the detector side while with 100k or so you should also get a plenty large signal. That would still be rather high impedance for a analog input; I'd buffer the photo detector output with an opamp so you don't get problems with the input capacitance of the adc on your arduino.

As I just created a test-setup using the Ramps board and the IR sensor the area of the schematics on my first post is the only thing connected to my arduino. TMC2130 is on X position of my test (Ramps 1.3) setup.

On my example sketch (in the video and code above) I used digitalRead.

The sensor is choosen properly and approved by my customer (which machined all the aluminium and acrylic parts and 3d printed the holder for the sensor).
The video shows that detection in general works well (everytime the hole is in the right position the display turns on and off properly) - as long as I'm not using a serial connection. When using the serial monitor everything starts going crazy - that's why I just build the test-setup using the old ramps board...

Before I designed the hardware, I tested the sensor on my laboratory PSU. It works fine - as long as I'm not using the serial monitor....which makes developing really, really difficult (I wanted the ramps test setup to be able to analyze in realtime using the serial monitor - but the behavior it the same as on the final PCB...).

@koraks: thanks for your reply. So I'm going to build an impedance converter today.
Luckily the cable used hast 2 free veins!

Before I changet the value to 10 Megs, I tested using 33K which didn't work at all...
So using 10Megs shows alternating values as the impedance of the AtMega2560 ADC has a too low impedance?

As soon as I add the OP amp, how would you guys start coding the detection?
I've been looking for tutorials...but still don't know where to start from.

What is the white box thats display is showing you the detected hole?

Use the output of that to do your detection, it looks like it has all the smarts to run the reflective sensor.

Tom... :smiley: :+1: :coffee: :australia:

That's the original PCB I designed. But the big disadvantage is: I cannot connect both power PSU and USB at the same time :frowning: That's another reason I build the Ramps test-setup. But both circuits show the same problem: As soon as I turn on serial communication, the values start dancing :smiley:

I'll create an impedance converter using an OP later and we'll see if this solves my problem :slight_smile:

But I still need to know how to detect the unique stop-marker and all the other holes.
When entering an hole, I get alternating values th the edge. So I guess I need to sort our all values I don't need...but no idea where to start from.

I can't guarantee that's the only cause of your problem, but it certainly isn't a good idea to take a signal in the several Meg-Ohm's region as an input for your ADC channel. See datasheet of the Atmega2560, page 275:

The ADC is optimized for analog signals with an output impedance of approximately 10kļ— or less. If such a source
is used, the sampling time will be negligible. If a source with higher impedance is used, the sampling time will
depend on how long time the source needs to charge the S/H capacitor, which can vary widely. The user is recommended to only use low impedant sources with slowly varying signals, since this minimizes the required charge
transfer to the S/H capacitor.

Make a USB lead with the 5V wire open circuit, as long as both USB and your external circuit share the same gnd, you should be fine.
I made one for a work project because the project was powered by an automotive system and the current consumption was up to 10A.

Do you have a DMM?
This looks like medical/laboratory sample/test gear.
The sensor is probably sensing the reflection from disk surface and not the hole, and it just has inverted output logic.

Tom... :smiley: :+1: :coffee: :australia:

Sure I have a DMM here, as well as an Rigol DS1054z.

Will an TDA2822 suite well as an impedance converter? I've never build one... Or should I go for an LM358P?

What I also have right here in front of me is:
JRC 4558D (but that will not suite as I don't have a symmetrical PSU in this circuit...)

//Edit: shall I place the op amp close to the sensor? The wire between sensor and PCB is nearly 2m long...

//edit2: Make a USB lead with the 5V wire open circuit <= This won't work. I need the 5V USB for the CH340 USB seriell converter on my PCB. That's the reason I'm using the Ramps board for developing now :wink:


Your serial converter doesn't have an isolation jumper?
So the convert is USB powered, but it doesn't feed to the controller?
What converter have you got.

I cannot see why you are having problems reading the sensor if you made a PCB that works in your video clip.
Why can you use that?
What has it got in it?
What sort of connections/interface does it make to the sensor?
Can you got a schematic of it?

Tom... :smiley: :+1: :coffee: :australia:
PS. What Arduino controller are you using?

Uhm, no, that wouldn't be my choice as it's an audio power amplifier intended for portable devices. It also seems to be quite ancient.

Any modern opamp would do, really. LM358 would be OK.

Isolationjumper? Don't know what you mean. Do you have an example schematics for this?
Converter is an SMD CH340.

In the video clip the Adruino is connected to stepper, sensor and PSU only. If I'm using USB I don't have enough power for the stepper and the ADC values start going crazy. As long as I'm not using serial connection between mycomputer and the Arduino (which is an AtMega2560 as mentioned above - soldered on my custom PCB).

The sensor is connected using an 2m long 8pole cable. 4 poles are used for the IR sensor, 2 poles are for a FAN (either the sensor is running or the fan), and 2 unused poles (which I can use to power an impedance converter close to the sensor if neccessary).

Would you rather go for the TDA2822, the LM393N or the LM358 for the impedance converter?
I can power it with 5V and GND symmetrical supply available!