Arduino C random LED code not turning on all the LEDs - c

I'm coding with the Arduino Uno software and have ran into a problem. I'm trying to turn 8 LEDs on in a random order and then turn them all off at once. My problem is that the LEDs would turn on the same ones multiple times which in the end would not turn them all on. This makes the circuit not give the effect that I'm looking for. I've been working to fix the problem for about two hours and have tried many fixes which haven't worked. Here's the code that I'm working with:
void randomLED()
{
int i;
int index;
int delayTime;
int tracker;
int ledPin1 = ledPins[0];
int ledPin2 = ledPins[1];
int ledPin3 = ledPins[2];
int ledPin4 = ledPins[3];
int ledPin5 = ledPins[4];
int ledPin6 = ledPins[5];
int ledPin7 = ledPins[6];
int ledPin8 = ledPins[7];
boolean ledPinOne = digitalRead(ledPin1);
boolean ledPinTwo = digitalRead(ledPin2);
boolean ledPinThree = digitalRead(ledPin3);
boolean ledPinFour = digitalRead(ledPin4);
boolean ledPinFive = digitalRead(ledPin5);
boolean ledPinSix = digitalRead(ledPin6);
boolean ledPinSeven = digitalRead(ledPin7);
boolean ledPinEight = digitalRead(ledPin8);
for (i = 0; i < 8; i++) {
bailout:
index = random(8); // pick a random number between 0 and 7
if (ledPinOne != HIGH && index == 0 || ledPinTwo != HIGH && index == 1 || ledPinThree != HIGH && index == 2 || ledPinFour != HIGH && index == 3 || ledPinFive != HIGH && index == 4 || ledPinSix != HIGH && index == 5 || ledPinSeven != HIGH && index == 6 || ledPinEight != HIGH && index == 7){
digitalWrite(ledPins[index], HIGH); // turn LED on
}
delay(100); // pause to slow down
}
delay(1000);
for (i = 0; i < 8; i++){
digitalWrite(ledPins[i], LOW);
}
}
I have a large if statement because I needed to have separate conditions for each LED to turn on. These condition were needed because the random number generator would turn on the same LEDs twice which I didn't want. I was hoping that putting all of these conditions in and if statement would make the LEDs act how I wanted. I've tried changing the == and != in the if statement to every combination and it still didn't work. I'm hoping I can find and answer to my problem here that'll fix my problem.

There are multiple problems with your code. You are picking 8 random numbers because you want to have all 8 LEDs lit at the end, but what if you get the same number twice? So you have to somehow make sure that you pick a number that corresponds to a LED that is not already lit. Another problem with your code is that you read each LED pin only once, outside the loop. So when you are checking each pin in your large if-statement the values are not up to date.
Here is a quick but bad way of solving both these issues:
int numberOfLEDsLit = 0;
while (numberOfLEDsLit < 8) {
int index = random(8);
int ledLit = digitalRead(ledPins[index]);
if (ledLit == LOW) {
digitalWrite(ledPinds[index], HIGH);
numberOfLEDsLit++;
}
}
Basically you pick a random led, if it is not lit then light it otherwise do nothing. Continue until all 8 LEDs are lit.

Taking a look at the reference for random()
If it is important for a sequence of values generated by random() to differ, on subsequent executions of a sketch, use randomSeed() to initialize the random number generator with a fairly random input, such as analogRead() on an unconnected pin.
So you need to call randomSeed(seed) just before your random() call if you want the sequences to be different on each run of the program.

Related

Use Arduino to generate sin wave modulated by gold code

I am trying to use Arduino to generate sin wave and gold code is used to determine when the wave will have a phase shift. However, the output is not performed as I expected. Sometimes, it does not occur any phase shift for consequent ten cycles, which should not happen according to our definition of gold code array. Which part of the code could I try to fix the problem?
int gold_code[]={1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,-1,-1, 1,1,-1,1,1,1,-1,1,-1,1,1,-1,1,1,-1,-1,-1,-1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,1,1,1,-1,1,1,-1, -1, 1, 1,1,-1,-1,1,-1,-1,1,1,1};
void loop()
{
int n = sizeof(gold_code)/sizeof(gold_code[0]);
byte bsin[128];
int it;
unsigned long tm0;
unsigned int tm;
for(int i=0;i<128;i++)
{
bsin[i] = 8 + (int)(0.5 + 7.*sin( (double)i*3.14159265/64.));
}
int count=0;
int count1=0;
Serial.println(n);
tm0 = micros();
while(true)
{
tm = micros() - tm0;
if(tm > 511)
{
tm0 = tm0+512;
tm -= 512;
count++;
//Serial.println(gold_code[count%n]);
}
tm = (tm >> 2) ;
if(gold_code[count%n]==0){
PORTB = bsin[tm];
}
else{
PORTB = 16-bsin[tm];
}
}
}
The variable count eventually overflows and becomes negative. This, in conjunction with the modulo operation is a sign (pun intended) of a disaster waiting to happen.
Use a different method for limiting the value of count to the bounds of your gold_codearray.
You should expect a significant increase in frequency after removing the modulo operation, so you may need to add some pacing to your loop.
The pacing in your loop is wrong. Variable count increments 4 times as fast as your phase counter.
Also, #Edward Karak raises a valid point. To do a proper phase shift, you should add (or subtract) from tm, not from the sin value.
[EDIT] I was not quite happy with the way the phase shift is handled. It just doesn't feel right to advance the gold counter at the same pace as the phase counter. So I added a separate timer for that. Advances in the gold_code array every 8 microseconds for now, but you can change it to whatever you're supposed to have.
as in:
unsigned char tm0 = 0;
unsigned char tm0_gold = 0;
const unsigned char N = sizeof(gold_code) / sizeof(gold_code[0]);
unsigned char phase = 0;
for(;;)
{
// pacing for a stable frequency
unsigned char mic = micros() & 0xFF;
if (mic - tm0_gold >= 8)
{
tm0_gold = mic;
// compute and do the phase shift
if (++count >= N)
count -= N;
if (gold_code[count] > 0) // you have == 0 in your code, but that doesn't make sense.
phase += 16; // I can't make any sense of what you are trying to do,
// so I'll just add 45° of phase for each positive value
// you'll probably want to make your own test here
}
if (mic - tm0 >= 4)
{
tm0 = mic;
// advance the phase. keep within the LUT bounds
if (++phase >= 128)
phase -= 128;
// output
PORTB = bsin[phase];
}
}
For frequency stability, you will want to move the sine generator to a timer interrupt, after debugging. This will free up your loop() to do some extra control.
I don't quite understand why count increments as fast as the phase counter.
You may want to increment count at a slower pace to reach your goal.

Arduino problems with array

Hi I am working on a project lighting my house lights using an Arduino.
I have it working in a basic form, now I want to store the previous state of the light switch. I am using an array that stores the current state of the switch so it can be compared on the next loop. I have 7 switches, I have created it so one switch has the ability to turn on many lights, if required.
I need to store the previous state as the next part is to introduce web control the test project for this is already written
The strange thing is zones 7/8 work perfect. the other zones turn on, but don't turn off. When I turn on another switch a light may go off if it's switch is in the off position.
If I remove the condition for the previous state check all switches perfectly fine.
const int zone2[] = {8,13,0};
const int zone3[] = {11,0};
const int zone4[] = {7,0};
const int zone5[] = {9,0};
const int zone6[] = {12,0};
const int zone7[] = {6,0};
const int zone8[] = {14,0};
const int * zones[]={zone2,zone3,zone4,zone5,zone6,zone7,zone8};
int buttonState[] = {0,0}; // variable for reading the pushbutton status
int previousState[]={0,0,0,0,0,0,0,0}; // array for holding the previous state of the input button
void setup()
{
//initialize the output pins that will control lights
pinMode(6,OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9,OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13,OUTPUT);
pinMode(14,OUTPUT);
// initialize the pushbutton pin as an input:
//set all light switches to the same block ie pins 30 - 35
byte i;
//this loop sets all the 30-35pins as inputs
for (i=30;i< 37;i++) {
pinMode(i, INPUT);
digitalWrite(i,HIGH); // this makes it connect to the internal resistor
}
}
void loop()
{
int arrayPosition;
for (int z = 0; z < 7; ++z)//zero based array needs to be as many as there are zones!!!
{
buttonState[z] = digitalRead(z+30);
for (arrayPosition = 0;zones[z][arrayPosition] ; arrayPosition++)
{
if ((buttonState[z] == HIGH) ) && (previousState[z] == LOW )) {
// turn LED on:
digitalWrite(zones[z][arrayPosition],HIGH);
}
else if ((buttonState[z] == LOW) && (previousState[z] == HIGH )) {
// turn LED off;
digitalWrite(zones[z][arrayPosition],LOW);
}
}
//each light assigned to the zone has been turned on or off, now set previousstate
//the statement is here the inner loop has finsihed turning lights on or off that belong to that zone
previousState[z] = buttonState[z];
}
}
You allocate two elements to the array buttonState, but you are accessing seven:
[…]
int buttonState[] = {0,0};
[…]
for (int z = 0; z < 7; ++z)
{
buttonState[z] = digitalRead(z+30);
[…]
You should increase the number of elements in the buttonState array to be as many as you actually need.
It might be better to define the size of the arrays at a single place:
#define NUM_ZONES (7)
[…]
const int * zones[NUM_ZONES]={zone2,zone3,zone4,zone5,zone6,zone7,zone8};
int buttonState[NUM_ZONES] = {0,0,0,0,0,0,0};
int previousState[NUM_ZONES]={0,0,0,0,0,0,0};
[…]
for (int z = 0; z < NUM_ZONES; ++z)
[…]
This will also reveal that your previousState array is larger than needed (the compiler will complain that you have too many initialisers for that array). It is then important to re-use that constant everywhere instead of writing the magic number 7.

Selectively ignoring parts of a randomly generated sequence of numbers (in C)

I have a question that may be hard to understand -- but I will try my best to explain.
I'm programming the Simon Game in C. This implementation specifically read/writes to a hardware DAQ module that has a 4 LED display, and 4 corresponding toggle switches.
As per the rules of the Game, I've seeded and generated a random sequence of numbers between 0 and 3 (sequence length is arbitrarily 5). In the Game, if the player presses the wrong switch (i.e. blue is shown but you press green), the game ends and restarts.
The way I've set up the Game looks like this:
(I haven't included the code for function "blinkLED" here -- it turns the actual LED on/off.)
void runSimon(void){
int sequence[MAX_SEQ_LEN];
int i;
int count = 0;
// Seeds the random number generator.
srand((unsigned)time(NULL));
// Generate the random LED sequence & store it as an array.
for (i = 0; i < MAX_SEQ_LEN; i++){
sequence[i] = (rand() % NUM_LEDS);
}
// The game begins!
while (continueSuperLoop() == TRUE){
// Loop the game while the sequence length is less than the pre-defined maximum (currently it's 5).
while (count < MAX_SEQ_LEN){
for (i = 0; i <= count; i++){
// Blink the first 'count' LEDs in the sequence, one at a time.
blinkLED(sequence[i], 1, ONE_SEC);
//
//
//THE ISSUE SHOULD BE HERE (!)
//
// Monitors whether or not the player has made a mistake...if so, blink the red LED thrice, then restart the game.
if (digitalRead(sequence[ !i ] == SWITCH_ON)){
blinkLED(LED_1_R, 3, HALF_SEC);
Sleep(3 * ONE_SEC);
continue;
}
// Monitors whether or not the correct switch is being pressed -- waits for it to be released
while (digitalRead(sequence[i]) == SWITCH_ON){}
}
count++;
}
// If 'count' is equal to 'MAX_SEQ_LEN', the green LED blinks 3x to indicate the player has won .
if (count == MAX_SEQ_LEN){
blinkLED(LED_0_G, 3, HALF_SEC);
Sleep(3 * ONE_SEC);
}
}
}
Where I indicated an issue, I'm not sure how the "digitalRead(sequence[ ! i ]" behaves; I need this line to read every switch that's not supposed to be pressed.
I don't think the compiler understands what I'm trying to do here, though -- for example, if the first number in the sequence is 3 (representing the 4th LED), I need to specify that every other number (0, 1, 2) and its corresponding switch should not be pressed.
Would a solution be to store the current number in the sequence, having a set of four TRUE/FALSE flags for each LED, and monitoring the three non-current numbers and their corresp. switches to see if they are pressed?
I'm getting quite frustrated with writing this program. I'm pretty new to programming. Any help is appreciated.
I'm not sure I understand the rules of this game correctly but one thing that jumps out instantly is
digitalRead(sequence[ !i ]
I think you want
!digitalRead(sequence[ i ]
Also, you need to fix your game flow. Right now it's:
1. Light LED.
2. Check if user pressed the right button.
You need to wait for some time before checking a switch or wait for ANY switch to be pressed and see if it's the correct one. So something like this:
1. Light LED.
2. Wait for timeout or ANY switch to be pressed.
3. If timeout: error
4. else: check if switch that was pressed is correct.
In C, ! operator is a unary NOT. When applied to an integer i, it is equivalent to if (i == 0) return 1; else return 0;. Then you are using !i as an index for sequence array, so it will be either sequence[0] or sequence[1], and clearly this is not what you want. Also your == is inside of digitalRead call :)
I would suggest explicitly checking for every other button not to be pressed. Like this:
int isOtherPressed = 0;
for (ledId = 0; ledId < NUM_LEDS; ledId++) {
if (ledId != sequence[i] && digitalRead(ledId) == SWITCH_ON) {
isOtherPressed = 1;
}
}
if (isOtherPressed) {
// restart the game
}
However, I'm suspicious about the whole gameplay you have, but maybe it's just because I don't know how digitalRead works. For example, the way you use continue doesn't seem to stop the game. Maybe you meant break?

How to optimize C for loop for font rendering on oled display

I need to optimize this function: Any strange way to optimize the for loop? (early break i think can't be possible)
void SeeedGrayOLED::putChar(unsigned char C)
{
if(C < 32 || C > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
{
C=' '; //Space
}
uint8_t k,offset = 0;
char bit1,bit2,c = 0;
for(char i=0;i<16;i++)
{
for(char j=0;j<32;j+=2)
{
if(i>8){
k=i-8;
offset = 1;
}else{
k=i;
}
// Character is constructed two pixel at a time using vertical mode from the default 8x8 font
c=0x00;
bit1=(pgm_read_byte(&hallfetica_normal[C-32][j+offset]) >> (8-k)) & 0x01;
bit2=(pgm_read_byte(&hallfetica_normal[C-32][j+offset]) >> ((8-k)-1)) & 0x01;
// Each bit is changed to a nibble
c|=(bit1)?grayH:0x00;
c|=(bit2)?grayL:0x00;
sendData(c);
}
}
}
I've got a font in the array hallfetica_normal, is an array of array of uint8_t, that maybe compressed or something like that?
This code run on a arduino, ad i've to run a countdown from 500 to 0 with one unit down every 10/20ms.
EDIT
This is the new code after yours indication, thanks all:
I'm looking to organise the font differently to permit less call to pgm_read_byte.. (something like changing the orientation... i wonder)
void SeeedGrayOLED::putChar(unsigned char C)
{
if(C < 32 || C > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
{
C=' '; //Space
}
char c,byte = 0x00;
unsigned char nibble_lookup[] = { 0, grayL, grayH, grayH | grayL };
for(int ii=0;ii<2;ii++){
for(int i=0;i<8;i++)
{
for(int j=0;j<32;j+=2)
{
byte = pgm_read_byte(&hallfetica_normal[C-32][j+ii]);
c = nibble_lookup[(byte >> (8-i)) & 3];
sendData(c);
}
}
}
}
Well, you seem to be reading the same byte twice in a row unnecessarily via pgm_read_byte(&hallfetica_normal[C-32][j+offset]). You could load that once into a local variable.
Additionally, you could avoid the if(i>8){ check per iteration by breaking up the code into two loops; one where i goes from 0 to 8 and another where it goes from 9 to 15. (Although I suspect you really intended >= here, making the loop boundaries 0-7 then 8-15.) That also means things like offset become constant values, which will help.
In an effort to make the inner loop as fast as possible, I'd try to get rid of all branching with a lookup table and see whether that helped.
First, I'd define the lookup table outside the loop:
/* outside the loop */
unsigned char h_lookup[] = { 0, grayH };
unsigned char l_lookup[] = { 0, grayL };
Then inside the loop, since you're testing the least-significant bit, you can use that as an index into the lookup table. If it's clear, then the lookup index will be 0. If it's set, then the lookup index will be 1:
/* inside the loop */
byte = pgm_read_byte(&hallfetica_normal[C-32][j+offset]);
c = h_lookup[((byte >> (8-k)) & 0x01)] |
l_lookup[((byte >> (8-k-1)) & 0x01)]
sendData(c);
Since you're masking and testing 2 adjacent bits, 8-k and 8-k-1, you could list all 4 possibilities in a single lookup table:
/* Outside loop */
unsigned char nibble_lookup[] = { 0, grayL, grayH, grayH | grayL };
And then the lookup becomes dramatically simplified.
/* loop */
byte = pgm_read_byte(&hallfetica_normal[C-32][j+offset]);
c = nibble_lookup[(byte >> (8-k)) & 3];
sendData(c);
The other answer has addressed what to do about the branches in the top part of your inner loop.

Arduino output pin outputs random activity

I am working on an Arduino project controlling a DIY RC truck that reads the output pins of an RC reciever and is supposed to PWMs a couple of pins accordingly. The pins are hooked onto a motor controller that takes PWM.
That is where the problem comes in. My reverse is working perfectly, but on the pin that does forward, I only get random activity. I'm using the Arduino Mega 2560.
Here is the code. The problem has been posted below it:
#include <Servo.h>
//Create variables for three channels
int RXCH[3];
volatile int RXSG[3];
int RXOK[3];
int PWMSG[3];
byte vooruit;
byte achteruit;
Servo stuur;
int mv = 13;
int ma = 10;
void setup() {
Serial.begin(115200);
stuur.attach(8);
//Assign PPM input pins. The receiver output pins are conected as below to non-PWM Digital connectors:
RXCH[0] = 6; //Throttle
RXCH[1] = 7; //Steering
//RXCH[2] = 5; //Nothing yet
//RXCH[3] = 2; //Nothing yet
//RXCH[4] = 7; //Nothing yet
//RXCH[5] = 8; //Nothing yet
for (int i = 0; i < 3; i++){
pinMode(RXCH[i], INPUT);
}
//TCCR1B = TCCR1B & 0b11111000 | 0x01;
//TCCR2B = TCCR2B & 0b11111000 | 0x01;
}
void loop() {
// Read RX values
for (int i = 0; i < 3; i++){ //For each of the 6 channels:
RXSG[i] = pulseIn(RXCH[i], HIGH, 20000); //Read the receiver signal
if (RXSG[i] == 0) { //Error catching
RXSG[i] = RXOK[i];
} else {
RXOK[i] = RXSG[i];
}
//Substitute the high values to a value between -255 and 255
PWMSG[0] = map(RXSG[0], 1000, 2000, -255, 255);
//Servo values, calibrated according to my steering servo.
PWMSG[1] = map(RXSG[1], 1000, 2000, 24, 169);
//Make sure that the value stays within the desired boundaries.
constrain (PWMSG[i], -255, 255);
//For debugginf purposes
Serial.print(" || Ch: ");
Serial.print(i);
Serial.print(" / PWMSG: ");
Serial.print(PWMSG[i]);
}
delay (5);
// Car goes forwards
if (PWMSG[0] > 40)
{
MV();
}
// Car goes backwards
if (PWMSG[0] < -40)
{
MA();
}
// Car stops
else
{
stopmotor();
}
stuur.write(PWMSG[1]);
Serial.println();
}
void MV()
{
vooruit = PWMSG[0];
analogWrite (mv, vooruit);
digitalWrite (ma, LOW);
Serial.print(" vooruit: ");
Serial.print(vooruit);
}
void MA()
{
achteruit = abs(PWMSG[0]);
analogWrite (ma, achteruit);
digitalWrite (mv, LOW);
Serial.print(" achteruit: ");
Serial.print(achteruit);
}
void stopmotor()
{
digitalWrite (ma, LOW);
digitalWrite (mv, LOW);
}
I don't really know if the code is considered pretty, or if I made some basic mistakes for that matter.
This is one of my first projects that I tried to do the right way, making comments and such, all well commented criticism is welcome.
What the code is supposed to do:
Move the stick on the transmitter forwards, the car goes forwards, and speed should be according to position of the stick.
Move the stick on the transmitter backwards, the car goes backwards, and speed should be according to position of the stick.
Move stick on the transmitter left or right, the servo in the car should react according to the value the Arduino calculated. You might wonder why I don't place the servo directly on the transmitter. Well, that's because I have many more future things in mind with this project, and now I can calibrate it way easier.
Problem:
When I move the stick on the transmitter forwards, and the Serial monitor is open, I get the right values on the Serial monitor, but the LED present on pin 13 just randomly blinks, very dim I must say.
I already tried to replace things like byte with int, but it had no effect. The rest of the code works fine.
Using some new code, I get a Serial response from every "stage", except the final stages that controls the pins.
#include <Servo.h>
//Create variables for channels
Servo wheel;
int MFORWARD_PIN = 13;
#define MBACKWARD_PIN 10
#define WHEEL_PIN 8
#define THROTTLE_PIN 6
#define STEERING_PIN 7
void setup() {
Serial.begin(115200);
wheel.attach(WHEEL_PIN);
pinMode(THROTTLE_PIN, INPUT);
pinMode(STEERING_PIN, INPUT);
pinMode(MFORWARD_PIN, OUTPUT);
pinMode(MBACKWARD_PIN, OUTPUT);
//TCCR1B = TCCR1B & 0b11111000 | 0x01;
//TCCR2B = TCCR2B & 0b11111000 | 0x01;
}
void loop() {
int throttle = read_throttle();
int steering = read_steering();
delay (5);
throttle_handle(throttle);
steering_handle(steering);
}
// Read RX values
int read_throttle(){
int throttle = pulseIn(THROTTLE_PIN, HIGH, 20000);
throttle = map(throttle, 1000, 2000, -255, 255); //Substitute the high values to a value between -255 and 255.
constrain (throttle, -255, 255); //Make sure that the value stays within the desired boundaries.
//Serial.println(throttle);
}
int read_steering() {
int steering = pulseIn(STEERING_PIN, HIGH, 20000);
steering = map(steering, 1000, 2000, 24, 169); //Servo values, calibrated according to my steering servo.
constrain (steering, 24, 169); //Make sure that the value stays within the disired boundaries.
//Serial.println("steering");
}
void move_forward(int val) {
analogWrite (MFORWARD_PIN, val);
digitalWrite (MBACKWARD_PIN, LOW);
Serial.print(" vooruit: ");
Serial.print(val);
}
void move_backward(int val)
{
val = abs(val);
analogWrite (MBACKWARD_PIN, val);
digitalWrite (MFORWARD_PIN, LOW);
Serial.print(" achteruit: ");
Serial.print(val);
}
void move_stop()
{
digitalWrite (MFORWARD_PIN, LOW);
digitalWrite (MBACKWARD_PIN, LOW);
}
void throttle_handle(int throttle) {
//Serial.print("throttle");
if (throttle > 40) {
move_forward(throttle);
}
if (throttle < -40) {
move_backward(throttle);
}
else {
move_stop();
}
}
void steering_handle(int steering) {
wheel.write(steering);
// Serial.println("steering:");
// Serial.print(steering);
}
Unused index:
Everywhere you loop over three values, whereas you only use two items in the array. So you'd better change all your sizes to 2 instead of 3, or you can define a NB_INPUT constant at the top of your source code, that you can change easily for more flexibility:
#define NB_INPUT 2
...
for (int i = 0; i<NB_INPUT; ++i) {
...
RXOK in setup():
your comment about arrays is justified, the first bug I can see in your code is that you read from the RXOK array, whereas you did not put any values in it. If you're sure that RXSG gets only zeroes from pulseIn() on the first pass of the Read RX values loop it can be ok, but I doubt it is. e.g.:
for (int i=0; i<3; ++i)
RXOK[i] = 0;
So you should put values in RXOK values in setup().
constant indexes in a for loop:
Then you map() the values from 1000->2000 to -255->255 for RXSG[0] and RXSG[1] inside the for loop, which will be done for the three iterations. I'm not sure what you want there, but if you want to do it for constant indexes, you'd better do it outside of the loop. But as you're checking a constraint on the -255->255 domain for each value of the iteration loop, I think you may want to do it on relative values:
PWMSG[i] = map(RXSG[i], 1000, 2000, -255, 255);
but it seems the domain is dependent on the index, so you may want to make a couple of defines at the top of your source code:
#define THROTTLE_IDX 0
#define STEERING_IDX 1
and put your map() in a if statement:
if (i == THROTTLE_IDX)
PWMSG[i] = map(RXSG[i], 1000, 2000, -255, 255);
elif (i == STEERING_IDX)
PWMSG[i] = map(RXSG[i], 1000, 2000, 24, 169);
# add a else statement if you need to do a map for the other values of the array
constrain(PWMSG[i], -255, 255)
general algorithm
I'm not sure you really need an array for your use case. You'd better keep a few variables around and have a better use of functions for your code to be readable and less bugprone:
#define THROTTLE_PIN 6
#define STEERING_PIN 7
#define WHEEL_PIN 8
#define MFORWARD_PIN 13
#define MBACKWARD_PIN 10
Servo wheel;
// sets up the arduino
void setup() {
Serial.begin(115200);
wheel.attach(WHEEL_PIN);
pinMode(THROTTLE_PIN, INPUT);
pinMode(STEERING_PIN, INPUT);
}
// input data handling
int read_throttle() {
int throttle = pulseIn(THROTTLE_PIN, HIGH, 20000);
return map(throttle, 1000, 2000, -255, 255);
}
int read_steering() {
int steering = pulseIn(STEERING_PIN, HIGH, 20000);
return map(throttle, 1000, 2000, 24, 169);
}
// output actions handling
void move_forward(int val) {
analogWrite(MFORWARD_PIN, val);
digitalWrite(MBACKWARD_PIN, LOW);
// Serial.print...
}
void move_backward(int val) {
analogWrite(MFORWARD_PIN, val);
digitalWrite(MBACKWARD_PIN, LOW);
// Serial.print...
}
void stop_motor() {
digitalWrite(MFORWARD_PIN, LOW);
digitalWrite(MBACKWARD_PIN, LOW);
}
void handle_throttle(int throttle) {
if (throttle > 40)
move_forward(throttle);
elif (throttle < -40)
move_backward(throttle);
else
stop_motor();
}
// general algorithm
void loop() {
int throttle = read_throttle();
delay(5);
handle_throttle(throttle);
}
There are more code duplication, but sometimes it is better to duplicate code than to make a code almost unreadable, and hard to debug while not offering any kind of flexibility/modularity. And here are a few other things I found in your code that should be corrected:
Naming convention: try to use good names for your functions (two letters variables, or dutch variables are not a good idea, I'm not english native and I always avoid to use my own language based names in code even for code I don't share, you never know who will read your code in 2 days, 2 months, or 2 years).
globals: Try to avoid using global variables as much as possible. Declare only constant in the global scope : const int foo = 1; or preprocessor defines #define foo 1, so that you do not spend too much of the little RAM space you have on your arduino. The only exception to that rule, which is very specific to arduino development, are objects (like Servo in your code) that you need to declare globally so you can set them up in the setup() function, and use them in the loop() function.
If I extrapolate on what you've written, you may want to add a handle_steering() function such as:
void handle_steering(int steering) {
if (steering > NN)
turn_left(steering);
elif (steering < NN)
turn_right(steering);
else
keep_straight();
}
and change the loop() to :
void loop() {
int throttle = read_throttle();
int steering = read_steering();
delay(5);
handle_throttle(throttle);
handle_steering(steering);
}
To make it a more general case of handling dynamically and flexibly a number of features, you could keep a few arrays:
PIN[]: containing the pins,
DOM_MIN[]: containing the minimum of the features' domain (for the map),
DOM_MAX[]: containing the maximum of the features' domain (for the map),
BOUND_MIN[]: containing the minimum boundaries (for the handle_steering condition),
BOUND_MAX[]: containing the maximum boundaries (for the handle_steering condition),
ACTION[]: containing the pointers to functions.
and then your algorithm would look like:
int read_input(int i) {
int value = pulseIn(PIN[i], HIGH, 20000);
return map(value, 1000, 2000, DOM_MIN[i], DOM_MAX[i]);
}
int handle_action(int i, int value) {
if (value > BOUND_MIN[i])
*(ACTION[i])(value);
elif (value < BOUND_MAX[i])
*(ACTION[i])(value);
else
*(ACTION[i])(-1);
}
void loop() {
for (int i=0; i<NB_INPUTS; ++i) {
int value = read_input(i);
delay(5);
handle_action(i, value);
}
}
but as you're still not comfortable with arrays (and I assume pointers as well), I would not recommend going further that way for the time being. First do it simple and make it work and then you could try to factorize it following the idea I'm exposing here. But you're making a software that is embedded, where the RAM is rare and the processing power is low, while your code space is cheap. So it's one of the few occasions where you'd better want to make a more redundant code that will stay in program space, whereas you want to manipulate as little symbols in the RAM. That's why I'm not showing you how the arrays are being declared/defined, and how to handle function pointers, because I don't think that solution (where you were heading) is the right way to do what you want.
Always remember, simpler is better!
HTH

Resources