30 Days Lost in Space → Help Center

Coding Concepts

constrain()

Keeps a number within a range by clamping it. Too low becomes the minimum, too high becomes the maximum. You will use this constantly alongside map() and sensor readings.

What constrain() Does

int result = constrain(value, min, max);

| If value is... | result becomes... | |----------------|-------------------| | Less than min | min | | Greater than max | max | | Between min and max | value (unchanged) |

Some examples:

constrain(150, 0, 255)   -> 150   (in range, no change)
constrain(-20, 0, 255)   ->   0   (below min, clamped up)
constrain(300, 0, 255)   -> 255   (above max, clamped down)

Why You Need It

Sensor readings spike outside expected ranges

A photoresistor that normally reads 200-800 might return 1023 if a flashlight hits it, or 0 in complete darkness. If you feed that into analogWrite() (which expects 0-255), you have a problem.

map() does not clamp its output

This surprises people. map() happily produces values outside your target range if the input is outside the expected input range. Here is the pattern you will use constantly:

int raw = analogRead(A0);
int mapped = map(raw, 200, 800, 0, 255);     // could go negative or above 255
int safe = constrain(mapped, 0, 255);         // now guaranteed 0-255
analogWrite(ledPin, safe);

Without constrain(), a raw reading below 200 maps to a negative number. analogWrite() with a negative value wraps to a high brightness. That bug only shows up at the edges of your sensor range and is hard to track down.

Calculations can overflow

If you are adding or subtracting from a variable (like adjusting brightness with buttons), the value can drift past its useful range:

brightness = brightness + 10;
brightness = constrain(brightness, 0, 255);

Protecting Hardware

Servo motors

Servos can be damaged if driven past their mechanical limits. constrain() acts as a safety net:

int angle = map(analogRead(A0), 0, 1023, 0, 180);
angle = constrain(angle, 10, 170);  // stay away from mechanical stops
servo.write(angle);

PWM values

analogWrite() expects 0-255. If your value comes from any calculation, constrain it.

What constrain() Does NOT Do

It does not scale. constrain(500, 0, 255) returns 255, not a proportionally scaled value. That is what map() is for.

It does not wrap around. constrain(10, 0, 5) returns 5, not 0. For wrapping behavior, use modulo (%).

// Wrapping (not what constrain does):
menuIndex = menuIndex % numItems;  // 0,1,2,3,0,1,2,3,...

// Clamping (what constrain does):
menuIndex = constrain(menuIndex, 0, numItems - 1);  // stops at the ends

The map() + constrain() Pattern

This comes up so often it is worth memorizing:

int output = constrain(map(input, inMin, inMax, outMin, outMax), outMin, outMax);

Concrete examples:

// Potentiometer controlling LED brightness
int brightness = constrain(map(analogRead(A0), 0, 1023, 0, 255), 0, 255);

// Photoresistor controlling servo
int angle = constrain(map(analogRead(A1), 200, 800, 10, 170), 10, 170);

Common Mistakes

| Mistake | What Happens | Fix | |---------|-------------|-----| | Getting min and max backwards | Wrong results, no error | Second argument must be smaller than third | | Expecting it to scale values | constrain(1023, 0, 255) returns 255, not 64 | Use map() for scaling, constrain() for clamping | | Unsigned type problems | Negative values wrap to huge positives before constrain sees them | Do math with int, constrain, then cast to byte | | Hiding bad sensor data | Silently swallows spikes that might indicate wiring problems | Print a warning when values are out of range |