lesthegrngo Posted February 4, 2023 Posted February 4, 2023 Hi all I have completed my new Climb and Altimeter gauge PCB, which has four nanos, one each driving two OLED's for the BARO ALT and altimeter displays, one for the climb gauge direct and one via an A4899 stepper using a TCRT5000L IR sensor module to give a zero position. I had previously cannibalised an Arduino IR sensor module with success, but it was a fairly clumsy PCB assembly and also had outputs for the OLEDs requiring a lot of dangling wires. The new one is a lot better and needs only two wires, one RS485 connection and one 12v supply. However the new IR sensor set up is clearly nowhere near as sensitive as the old one, as while it works when tested, once behind the gauge fascia with the slit at zero it is not able to detect the pointer passing in front. I've verified using the following sketch that the digital output does change const int digital_pin = 6; const int analog_pin = A0; void setup(){ Serial.begin(9600); pinMode(digital_pin,INPUT); } void loop(){ Serial.print("Analog Reading="); Serial.print(analogRead(analog_pin)); Serial.print("\t Digital Reading="); Serial.println(digitalRead(digital_pin)); delay(1000); } Obviously the analog reading doesn't change, but if you move a piece of paper about an inch in front of the sensor when not behind the gauge fascia, the digital output goes from zero to 1 verified using the serial monitor. I used the following circuit (attached below) with two minor changes - I couldn't get an LM393 IC, so instead I had to use an LM339, which is essentially the same chip but with inputs for four devices rather than one, but functionally using the correct pins should be identical. The other change was that I could not get an 8.8K trim potentiometer, only a 10K item So I need to increase the sensitivity. It seems that the potentiometer makes very little difference to the sensitivity, there is a slight change but it is minimal. Is there any way to achieve this? Cheers Les
No1sonuk Posted February 4, 2023 Posted February 4, 2023 Could the needle be too close to be detected? Some useful info here: https://www.vishay.com/docs/80107/80107.pdf
lesthegrngo Posted February 4, 2023 Author Posted February 4, 2023 Thanks, but if anything bringing it closer makes it work better. I can get it working if I have a distance of 2mm or less between the pointer back and the gauge face, meaning about 4mm in total. I am playing with different materials for putting on the back of the pointer, and obviously highly reflective materials are giving better results. I am going to see if I can find some mirror finish film like the stuff they use for balloons to see if that helps. However I would still appreciate any suggestions about improving the ability to adjust the sensitivity. I'm wondering about the resistor values, whether changing any of those would help, but of course my intrinsic ignorance about electronics means I am probably talking out of my recharge socket (Red Dwarf reference there for those confused...) Les
No1sonuk Posted February 4, 2023 Posted February 4, 2023 (edited) The mirror finish balloon stuff is usually called Mylar. I've got what's called "speed tape" in the aviation industry. It's basically very thin self-adhesive aluminium that's used for temporary patching of aerodynamic surfaces. You could possibly try kitchen foil and double-sided tape or glue (or even just wrap it around the needle to test it). As for the electronics: The op-amp is set up as a comparator. The potentiometer is being used as a voltage divider to set the detection threshold. With the circuit you have there, it's set up to trigger the output LOW when the input created by the R3 and phototransistor voltage divider drops below what you have set on the potentiometer when the light falls on the sensor. Because it's used as a voltage divider, changing the potentiometer value will have no effect beyond changing how much current the overall curcuit uses. I don't think changing R3 will either. And remember that you're using a device with an A-D converter... You could get rid of the hardware comparator entirely and read the voltage from the phototransistor, then compare it digitally. Another, easier, option is to make the LED brighter: The datasheet for the TCRT5000L shows the LED forward current can be up to 60mA. With an LED forward voltage of 1.5V, and 5V supply, 390 ohms at R2 gives a current of just over 8.97mA. That means you could drop the resistor, R2, as far as 100 ohms and get 35mA to get a "brighter" LED. Still within the range, but the LED may get warm. Just remember not to go lower than 175 ohms (20mA) if you're going to drive the LED directly from an Arduino pin so you can turn it on and off as required. Edited February 4, 2023 by No1sonuk
lesthegrngo Posted February 5, 2023 Author Posted February 5, 2023 Mylar, that's the stuff. I have a roll of speed tape too, the problem is with it is that it ends up less like a mirror finish due to the way that it conforms to the surface, having a slightly frosted look. I'll see what I can source here I can swap the resistor easily enough to test it but if the worst comes to the worst I will just have to make the pointer (or at least the reflective part) sit very very closely to the gauge fascia By hardware comparator, you mean the Op-Amp, so (referring to the schematic) inputting what would go to the LM393 pin 3 directly to the nano input? Cheers Les
No1sonuk Posted February 5, 2023 Posted February 5, 2023 6 hours ago, lesthegrngo said: Mylar, that's the stuff. I have a roll of speed tape too, the problem is with it is that it ends up less like a mirror finish due to the way that it conforms to the surface, having a slightly frosted look. I'll see what I can source here If it can detect white paper at 1", it should be able to detect speed tape further away. 6 hours ago, lesthegrngo said: By hardware comparator, you mean the Op-Amp, so (referring to the schematic) inputting what would go to the LM393 pin 3 directly to the nano input? Yes. Have a look here (and note the smaller resistor value for the LED): https://www.digikey.com/en/maker/blogs/2022/how-to-use-a-phototransistor-with-an-arduino
lesthegrngo Posted February 12, 2023 Author Posted February 12, 2023 Sorry for the delay in getting back on this I tried a 200 ohm resistor, that seemed to do the trick, the gauge works well with that without risking the pointer fouling on the gauge face. The new PCB is so much better than the old one in every way Thanks as always for the input! Les 1
lesthegrngo Posted September 13, 2023 Author Posted September 13, 2023 Hi all The Altimeter works well in USB mode, but I simply cannot get it to function properly in RS485 mode. I have three other Nanos on the same PCB for the altimeter scrolling OLED, climb gauge and Baro Alt OLED. All work fine in RS485 mode so the shared RS485 traces and wiring is apparently OK. I momentarily considered the IR circuit with the resistors to maybe be contributory as there is a path through that from VCC to GND, but that would affect the other RS485 devices as it is common to them too. I have been back and forth through the PCB with a multimeter and can confirm that there are no open circuits, shorts, or any other apparent issues. With the 12v to the stepper driver connected, when you connect the RS485 cable it will instantly move the pointer to the zero position, so the sketch seems to at least be partially working. However thereafter despite the RX light flashing, not much else happens. It looks like the pointer is trying to move, but not properly, it gives the occasional twitch. The other point of note is that when I connect it on the same slave line as other devices, it makes them glitch occasionally too, however if it is on another slave line it does not affect the others. Can anyone give me a clue as to why it is not working in RS485 mode? //#define DCSBIOS_IRQ_SERIAL #define DCSBIOS_RS485_SLAVE 49 #define TXENABLE_PIN 2 #include <AccelStepper.h> #include "DcsBios.h" #include <Wire.h> struct StepperConfig { unsigned int maxSteps; unsigned int acceleration; unsigned int maxSpeed; }; class Vid29Stepper : public DcsBios::Int16Buffer { private: AccelStepper& stepper; StepperConfig& stepperConfig; inline bool zeroDetected() { return digitalRead(irDetectorPin) == 1; } unsigned int (*map_function)(unsigned int); unsigned char initState; long currentStepperPosition; long lastAccelStepperPosition; unsigned char irDetectorPin; long zeroOffset; bool movingForward; bool lastZeroDetectState; long normalizeStepperPosition(long pos) { if (pos < 0) return pos + stepperConfig.maxSteps; if (pos >= stepperConfig.maxSteps) return pos - stepperConfig.maxSteps; return pos; } void updateCurrentStepperPosition() { // adjust currentStepperPosition to include the distance our stepper motor // was moved since we last updated it long movementSinceLastUpdate = stepper.currentPosition() - lastAccelStepperPosition; currentStepperPosition = normalizeStepperPosition(currentStepperPosition + movementSinceLastUpdate); lastAccelStepperPosition = stepper.currentPosition(); } public: Vid29Stepper(unsigned int address, AccelStepper& stepper, StepperConfig& stepperConfig, unsigned char irDetectorPin, long zeroOffset, unsigned int (*map_function)(unsigned int)): Int16Buffer(address), stepper(stepper), stepperConfig(stepperConfig), irDetectorPin(irDetectorPin), zeroOffset(zeroOffset), map_function(map_function), initState(0), currentStepperPosition(0), lastAccelStepperPosition(0) { } virtual void loop() { if (initState == 0) { // not initialized yet pinMode(irDetectorPin, INPUT); stepper.setMaxSpeed(stepperConfig.maxSpeed); stepper.setSpeed(1000); initState = 1; } if (initState == 1) { // move off zero if already there so we always get movement on reset // (to verify that the stepper is working) if (zeroDetected()) { stepper.runSpeed(); } else { initState = 2; } } if (initState == 2) { // zeroing if (!zeroDetected()) { stepper.runSpeed(); } else { stepper.setAcceleration(stepperConfig.acceleration); stepper.runToNewPosition(stepper.currentPosition() + zeroOffset); // tell the AccelStepper library that we are at position zero stepper.setCurrentPosition(0); lastAccelStepperPosition = 0; // set stepper acceleration in steps per second per second // (default is zero) stepper.setAcceleration(stepperConfig.acceleration); lastZeroDetectState = true; initState = 3; } } if (initState == 3) { // running normally // recalibrate when passing through zero position bool currentZeroDetectState = zeroDetected(); if (!lastZeroDetectState && currentZeroDetectState && movingForward) { // we have moved from left to right into the 'zero detect window' // and are now at position 0 lastAccelStepperPosition = stepper.currentPosition(); currentStepperPosition = normalizeStepperPosition(zeroOffset); } else if (lastZeroDetectState && !currentZeroDetectState && !movingForward) { // we have moved from right to left out of the 'zero detect window' // and are now at position (maxSteps-1) lastAccelStepperPosition = stepper.currentPosition(); currentStepperPosition = normalizeStepperPosition(stepperConfig.maxSteps + zeroOffset); } lastZeroDetectState = currentZeroDetectState; if (hasUpdatedData()) { // convert data from DCS to a target position expressed as a number of steps long targetPosition = (long)map_function(getData()); updateCurrentStepperPosition(); long delta = targetPosition - currentStepperPosition; // if we would move more than 180 degree counterclockwise, move clockwise instead if (delta < -((long)(stepperConfig.maxSteps / 2))) delta += stepperConfig.maxSteps; // if we would move more than 180 degree clockwise, move counterclockwise instead if (delta > (stepperConfig.maxSteps / 2)) delta -= (long)stepperConfig.maxSteps; movingForward = (delta >= 0); // tell AccelStepper to move relative to the current position stepper.move(delta); } stepper.run(); } } }; /* modify below this line */ /* define stepper parameters multiple Vid60Stepper instances can share the same StepperConfig object */ struct StepperConfig stepperConfig = { 730, // maxSteps 2200, // maxSpeed 1000 // acceleration }; // define AccelStepper instance AccelStepper stepper(AccelStepper::DRIVER, 4, 5); //was 11, 10 // define Vid29Stepper class that uses the AccelStepper instance defined in the line above // v-- arbitrary name Vid29Stepper alt100ftPointer(0x107e, // address of stepper data stepper, // name of AccelStepper instance stepperConfig, // StepperConfig struct instance 6, // IR Detector Pin (must be HIGH in zero position) 0, // zero offset [](unsigned int newValue) -> unsigned int { /* this function needs to map newValue to the correct number of steps */ return map(newValue, 65535, 0, 0, stepperConfig.maxSteps - 1); }); void setup() { DcsBios::setup(); } void loop() { DcsBios::loop(); } Cheers Les
Recommended Posts