This program is a simple program designed to plot at the same time both your & Uc on the serial monitor. Arduino runs through the first for loop & plot the F1 function and after that does the same with F2. My objective is to plot them both at the same time.
My idea is to actually take a small fraction of time, let's say 10 ms, to plot F1 & the next 10 ms to plot F2, but I don't know how to write this down. I think the millis function is the solution, but I'm not quite sure how to implement it.
const short int R = 5000;
const float C = 0.0005;
const float TE = 0.1;
const float Tau = R*C;
const short int E = 5;
float t, Tinit,Tfin;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
//F1
for ( t = 0; t <= 20; t = t+TE)
{
float Ur = E*exp(-t/Tau);
Serial.println (Ur);
}
//F2
for ( t = 0; t <= 20; t = t+TE)
{
float Uc = E*(1-exp(-t/Tau));
Serial.println (Uc);
}
}
Thread can be used to solve your problem . It has a huge documentation , it is widely used library for Arduino(unofficial).
Give it a try.
It will be easy for you, if you see these :
Example - 1 (thread instance example)
Example - 2 (callback example)
Example - 3 (It is still buggy , but I think it will help)
If you want to do it without libraries , then you need to create two functions , without those loops . Like
void f1()
{
float Ur = E*exp(-t/Tau);
Serial.println (Ur);
}
void f2()
{
float Uc = E*(1-exp(-t/Tau));
Serial.println (Uc);
}
Now inside "void loop()" you can implement the basic logic of threading , which will be pretty rough , but fulfill your requirements. Like :
void loop() {
unsigned long now = millis();
static unsigned long last_finger_update;
if (now - last_finger_update >= FINGER_UPDATE_PERIOD) {
last_finger_update = now;
f1();
}
static unsigned long last_wrist_update;
if (now - last_wrist_update >= WRIST_UPDATE_PERIOD) {
last_wrist_update = now;
f2();
}
}
You have to declare two variables
const unsigned long FINGER_UPDATE_PERIOD = 1000;
const unsigned long WRIST_UPDATE_PERIOD = 1000;
All time units are in milliseconds. This strategy is collected from internet.
The most deterministic way of handling this is simply:
for (t = 0; t <= 20; t = t + TE) {
float Ur = E*exp(-t/Tau);
float Uc = E*(1-exp(-t/Tau));
Serial.println (Ur);
Serial.println (Uc);
}
More generally, you can implement a primitive resource scheduler:
while (true) {
task_one();
task_two();
}
You can do that Easily if you run RTOS in MCU as you know other solutions will also be sequential...
I've been using TridentTD_EasyFreeRTOS library it has easy way of having multiple tasks and controlling them in different sketch files..
Related
I'm trying to use a teensy 4.1 as an interface between an encoder and ROS thanks to micro-ros (arduino version).
I would like to publish position of a wheel to the /jointState topic with the teensy but there is no example on the micro-ros arduino Github repo.
I've tried to inspect the sensormsgs/msg/jointState message struct but everything is a bit fuzzy and I don't understand how to make it works. I can't understand what is rosidl_runtime_c__double__Sequence type.
I've tried several things but I always get an error about operand types
no match for 'operator=' (operand types are 'rosidl_runtime_c__String' and 'const char [18]')
msg.name.data[0] = "drivewhl_1g_joint";
Here is my arduino code
#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <sensor_msgs/msg/joint_state.h>
rcl_publisher_t publisher;
sensor_msgs__msg__JointState msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
#define LED_PIN 13
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}
void error_loop(){
while(1){
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
//
//Do not work
//msg.name=["drivewhl_1g_joint","drivewhl_1d_joint","drivewhl_2g_joint","drivewhl_2d_joint"];
//msg.position=["1.3","0.2", "0","0"];
msg.name.size = 1;
msg.name.data[0] = "drivewhl_1g_joint";
msg.position.size = 1;
msg.position.data[0] = 1.85;
}
}
void setup() {
set_microros_transports();
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
delay(2000);
allocator = rcl_get_default_allocator();
//create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support));
// create publisher
RCCHECK(rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, JointState),
"JointState"));
// create timer,
const unsigned int timer_timeout = 1000;
RCCHECK(rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback));
// create executor
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor, &timer));
}
void loop() {
delay(100);
RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)));
}
I'm a beginner with Ros and C, it may be a very dumb question but I don't know how to solve it. Thanks for your help !
rosidl_runtime_c__String__Sequence is a structure used to old string data that is to be transmitted. Specifically it is a sequence of rosidl_runtime_c__String data. You're running into an error because rosidl_runtime_c__String is also a struct itself with no custom operators defined. Thus, your assignment fails since the types are not directly convertible. What you need to do instead is use the rosidl_runtime_c__String.data field. You can see slightly more info here
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
//msg.name=["drivewhl_1g_joint","drivewhl_1d_joint","drivewhl_2g_joint","drivewhl_2d_joint"];
//msg.position=["1.3","0.2", "0","0"];
msg.name.size = 1;
msg.name.data[0].data = "drivewhl_1g_joint";
msg.name.data[0].size = 17; //Size in bytes excluding null terminator
msg.position.size = 1;
msg.position.data[0] = 1.85;
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
}
}
I also spent quite some time trying to get publishing JointState message from my esp32 running microros, and also couldn't find working example. Finally, i was successful, maybe it will help someone.
In simple words:
.capacity contains max number of elements
.size contains actual number of elements (strlen in case of string)
.data should be allocated as using malloc as .capacity * sizeof()
each string within sequence should be allocated separately
This is my code that allocates memory for 12 joints, named j0-j11. Good luck!
...
// Declarations
rcl_publisher_t pub_joint;
sensor_msgs__msg__JointState joint_state_msg;
...
// Create publisher
RCCHECK(rclc_publisher_init_default(&pub_joint, &node,
ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, JointState),
"/hexapod/joint_state"));
//Allocate memory
joint_state_msg.name.capacity = 12;
joint_state_msg.name.size = 12;
joint_state_msg.name.data = (std_msgs__msg__String*) malloc(joint_state_msg.name.capacity*sizeof(std_msgs__msg__String));
for(int i=0;i<12;i++) {
joint_state_msg.name.data[i].data = malloc(5);
joint_state_msg.name.data[i].capacity = 5;
sprintf(joint_state_msg.name.data[i].data,"j%d",i);
joint_state_msg.name.data[i].size = strlen(joint_state_msg.name.data[i].data);
}
joint_state_msg.position.size=12;
joint_state_msg.position.capacity=12;
joint_state_msg.position.data = malloc(joint_state_msg.position.capacity*sizeof(double));
joint_state_msg.velocity.size=12;
joint_state_msg.velocity.capacity=12;
joint_state_msg.velocity.data = malloc(joint_state_msg.velocity.capacity*sizeof(double));
joint_state_msg.effort.size=12;
joint_state_msg.effort.capacity=12;
joint_state_msg.effort.data = malloc(joint_state_msg.effort.capacity*sizeof(double));
for(int i=0;i<12;i++) {
joint_state_msg.position.data[i]=0.0;
joint_state_msg.velocity.data[i]=0.0;
joint_state_msg.effort.data[i]=0.0;
}
....
//Publish
RCSOFTCHECK(rcl_publish(&pub_joint, &joint_state_msg, NULL));
I've written this code to receive a series of char variable through USART6 and have them stored in a string. But the problem is first received value is just a junk! Any help would be appreciated in advance.
while(1)
{
//memset(RxBuffer, 0, sizeof(RxBuffer));
i = 0;
requestRead(&dt, 1);
RxBuffer[i++] = dt;
while (i < 11)
{
requestRead(&dt, 1);
RxBuffer[i++] = dt;
HAL_Delay(5);
}
function prototype
static void requestRead(char *buffer, uint16_t length)
{
while (HAL_UART_Receive_IT(&huart6, buffer, length) != HAL_OK)
HAL_Delay(10);
}
First of all, the HAL_Delay seems to be redundant. Is there any particular reason for it?
The HAL_UART_Receive_IT function is used for non-blocking mode. What you have written seems to be more like blocking mode, which uses the HAL_UART_Receive function.
Also, I belive you need something like this:
Somewhere in the main:
// global variables
volatile uint8_t Rx_byte;
volatile uint8_t Rx_data[10];
volatile uint8_t Rx_indx = 0;
HAL_UART_Receive_IT(&huart1, &Rx_byte, 1);
And then the callback function:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == UART1) { // Current UART
Rx_data[Rx_indx++] = Rx_byte; // Add data to Rx_Buffer
}
HAL_UART_Receive_IT(&huart1, &Rx_byte, 1);
}
The idea is to receive always only one byte and save it into an array. Then somewhere check the number of received bytes or some pattern check, etc and then process the received frame.
On the other side, if the number of bytes is always same, you can change the "HAL_UART_Receive_IT" function and set the correct bytes count.
I'm new to arduino and trying to extract gps coordinate using neo 6m module using arduino but the loop is running till infinity. Can you please help me why it is not breaking.
void gpsEvent()
{
gpsString = "";
while (1)
{
while (gps.available() > 0) //Serial incoming data from GPS
{
char inChar = (char)gps.read();
gpsString += inChar;//store incoming data from GPS to temparary string str[]
i++;
// Serial.print(inChar);
if (i < 7)
{
if (gpsString[i-1] != test[i-1]) //check for right string
{
i = 0;
gpsString = "";
}
}
if (inChar == '\r')
{
if (i > 60)
{
gps_status = 1;
break;
}
else
{
i = 0;
}
}
}
if (gps_status)
break;
}
}
void get_gps()
{
gps_status = 0;
int x = 0;
while (gps_status == 0)
{
gpsEvent();
int str_lenth = i;
coordinate2dec();
i = 0;
x = 0;
str_lenth = 0;
}
}
I have called get_gps(); in the void setup() loop to initialize the system but the gpsEvent function which is used to extract the correct string from data is running till infinite can you pls help. The reference of the code is from https://circuitdigest.com/microcontroller-projects/arduino-based-accident-alert-system-using-gps-gsm-accelerometer
but have made few changes of my own but not in the programming for the gps module.
I think one of the errors is gpsString += inChar;.
This is not Python. You are adding the value of a character to a string pointer.
You should create a buffer with a maximum length, insert a char and check buffer overflow.
Also i seems not be defined. And in C is very bad practice to use global variables as you are doing. Keep one i in the function. Check again the string length.
In general, it seems you are using a language you do not know enough to write simple programs (string manipulation is basic on C). Either learn better C or look for a python implementation (or just link) of the gps library.
I am working with an Arduino and Processing with the Arduino library.
I get the error "The function bitWrite(byte, int, int) does not exist.";
it seams that processing + Arduino bitWrite function are not working together.
its raised due to this line:
arduino.bitWrite(data,desiredPin,desiredState);
my goal in this project is modifying a music reactive sketch to work with shift registers.
Here is my full code:
Arduino_Shift_display
import ddf.minim.*;
import ddf.minim.analysis.*;
import processing.serial.*;
import cc.arduino.*;
int displayNum = 8;
Arduino arduino;
//Set these in the order of frequency - 0th pin is the lowest frequency,
//while the final pin is the highest frequency
int[] lastFired = new int[displayNum];
int datapin = 2;
int clockpin = 3;
int latchpin = 4;
int switchpin = 7;
byte data = 0;
//Change these to mess with the flashing rates
//Sensitivity is the shortest possible interval between beats
//minTimeOn is the minimum time an LED can be on
int sensitivity = 75;
int minTimeOn = 50;
String mode;
String source;
Minim minim;
AudioInput in;
AudioPlayer song;
BeatDetect beat;
//Used to stop flashing if the only signal on the line is random noise
boolean hasInput = false;
float tol = 0.005;
void setup(){
// shift register setup
arduino.pinMode(datapin, arduino.OUTPUT);
arduino.pinMode(clockpin, arduino.OUTPUT);
arduino.pinMode(latchpin, arduino.OUTPUT);
arduino.digitalWrite(switchpin, arduino.HIGH);
//Uncomment the mode/source pair for the desired input
//Shoutcast radio stream
//mode = "radio";
//source = "http://scfire-ntc-aa05.stream.aol.com:80/stream/1018";
//mode = "file";
//source = "/path/to/mp3";
mode = "mic";
source = "";
size(512, 200, P2D);
minim = new Minim(this);
arduino = new Arduino(this, Arduino.list()[1]);
minim = new Minim(this);
if (mode == "file" || mode == "radio"){
song = minim.loadFile(source, 2048);
song.play();
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
beat.setSensitivity(sensitivity);
} else if (mode == "mic"){
in = minim.getLineIn(Minim.STEREO, 2048);
beat = new BeatDetect(in.bufferSize(), in.sampleRate());
beat.setSensitivity(sensitivity);
}
}
void shiftWrite(int desiredPin, int desiredState)
// This function lets you make the shift register outputs
// HIGH or LOW in exactly the same way that you use digitalWrite().
// Like digitalWrite(), this function takes two parameters:
// "desiredPin" is the shift register output pin
// you want to affect (0-7)
// "desiredState" is whether you want that output
// to be HIGH or LOW
// Inside the Arduino, numbers are stored as arrays of "bits",
// each of which is a single 1 or 0 value. Because a "byte" type
// is also eight bits, we'll use a byte (which we named "data"
// at the top of this sketch) to send data to the shift register.
// If a bit in the byte is "1", the output will be HIGH. If the bit
// is "0", the output will be LOW.
// To turn the individual bits in "data" on and off, we'll use
// a new Arduino commands called bitWrite(), which can make
// individual bits in a number 1 or 0.
{
// First we'll alter the global variable "data", changing the
// desired bit to 1 or 0:
arduino.bitWrite(data,desiredPin,desiredState);
// Now we'll actually send that data to the shift register.
// The shiftOut() function does all the hard work of
// manipulating the data and clock pins to move the data
// into the shift register:
arduino.shiftOut(datapin, clockpin, MSBFIRST, data);
// Once the data is in the shift register, we still need to
// make it appear at the outputs. We'll toggle the state of
// the latchPin, which will signal the shift register to "latch"
// the data to the outputs. (Latch activates on the high-to
// -low transition).
arduino.digitalWrite(latchpin, arduino.HIGH);
arduino.digitalWrite(latchpin, arduino.LOW);
}
void draw(){
if (mode == "file" || mode == "radio"){
beat.detect(song.mix);
drawWaveForm((AudioSource)song);
} else if (mode == "mic"){
beat.detect(in.mix);
drawWaveForm((AudioSource)in);
}
if (hasInput){ //hasInput is set within drawWaveForm
for (int i=0; i<displayNum-1; i++){
if ( beat.isRange( i+1, i+1, 1) ){
shiftWrite(i, 1);
lastFired[i] = millis();
} else {
if ((millis() - lastFired[i]) > minTimeOn){
shiftWrite(i, 0);
}
}
}
}
} //End draw method
//Display the input waveform
//This method sets 'hasInput' - if any sample in the signal has a value
//larger than 'tol,' there is a signal and the lights should flash.
//Otherwise, only noise is present and the lights should stay off.
void drawWaveForm(AudioSource src){
background(0);
stroke(255);
hasInput = false;
for(int i = 0; i < src.bufferSize() - 1; i++)
{
line(i, 50 + src.left.get(i)*50, i+1, 50 + src.left.get(i+1)*50);
line(i, 150 + src.right.get(i)*50, i+1, 150 + src.right.get(i+1)*50);
if (!hasInput && (abs(src.left.get(i)) > tol || abs(src.right.get(i)) > tol)){
hasInput = true;
}
}
}
void resetPins(){
for (int i=0; i<ledPins.length; i++){
arduino.digitalWrite(ledPins[i], Arduino.LOW);
}
}
void stop(){
resetPins();
if (mode == "mic"){
in.close();
}
minim.stop();
super.stop();
}
BeatListener
class BeatListener implements AudioListener
{
private BeatDetect beat;
private AudioPlayer source;
BeatListener(BeatDetect beat, AudioPlayer source)
{
this.source = source;
this.source.addListener(this);
this.beat = beat;
}
void samples(float[] samps)
{
beat.detect(source.mix);
}
void samples(float[] sampsL, float[] sampsR)
{
beat.detect(source.mix);
}
}
You can achieve the same thing using standard bitwise operators. To turn a bit on:
data |= 1 << bitNumber;
The right-hand side (1 << bitNumber) is a bit-shift operation to create a suitable bit-mask. It takes the single '1' bit and moves it left until it reaches the desired position. The bitwise-or assignment (|=) combines that new bit-mask with the existing bits in data. This turns the desired bit on, but leaves the rest untouched.
The code to turn a bit off is slightly different:
data &= ~(1 << bitNumber);
You can see the same bit-shift operation here. However, it's preceded by the unary negation operator (~). This swaps all the 1's for 0's, and all the 0's for 1's. The result is the exact opposite of the bit-mask we used before. You can't do a bitwise-or operation this time though, or else you'll turn all the other bits on. The bitwise-and assignment (&=) is used instead to combine this mask with the data variable. This ensures the desired bit is turned off, and the rest are untouched.
In your code, desiredPin is the equivalent of bitNumber.
A full explanation of how bitwise operations work can be quite lengthy. I'd recommend looking for a good tutorial online if you need more help with that.
There are also the bitSet and bitClear Arduino macros that make the code a little more readable than bit shifting and using AND and OR. The format is either bitSet(what_to_modify,bit_number) and bitClear(what_to_modify,bit_number). These translate into very efficient code and can be used to manipulate both, variables and hardware registers. So for example, if you wanted to turn on pin 13 on the Arduino UNO, you would first need to look up that Arduino pin 13 is actually pin 5 on PORTB of the Atmel atmega328 chip. So the command would be:
bitSet(PORTB,5);
I've wrote a program in C to connect the pc with a device by bluetooth. The program runs from terminal and the data received is shown in terminal as well. So far so good.
Now I've created a gui in qt, in which the main aim is to present the information which was before shown in terminal, now in qwtplots.
Well, I can so far connect the device with pc with the gui, but when I request the information form the device, it is shown in the terminal but the gui starts non responding.
here's the slot that requests the information from the device:
// Main Bluetooth
void gui::main_b()
{
// BLUETOOTH STUFF
int status, bytes_read;
int conta = 0;
FILE *data = NULL;
fd_set readmask;
struct timeval tv;
char buf[101];
int v, v1, v2;
tv.tv_sec = 0;
tv.tv_usec = 100000;
// Standard messages
char *startstr = "#START,0060,FF,12;";
write (sock, startstr, strlen (startstr));
data = fopen ("data.txt", "w");
while (conta < 100)
{
int i;
memset (buf, 0, 100);
FD_ZERO (&readmask);
FD_SET (sock, &readmask);
if (select (255, &readmask, NULL, NULL, &tv) > 0)
{
if (FD_ISSET (sock, &readmask))
{
int numb;
numb = read (sock, buf, 100);
// 12 bits
if (ui->comboBox->currentIndex() == 1)
{
if (numb == 14)
{
conta++;
//printf ("received %d bytes:\n", numb);
// print of counter
//printf ("%d,", buf[0]);
fprintf (data, "%d,", buf[0]);
for (i = 1; i < numb-1; i += 3)
{
v1 = buf[i] | ((buf[i + 1] & 0x0F) << 8);
v2 = buf[i + 2];
v2 = (v2 << 4) | ((buf[i + 1] & 0xf0) >> 4);
printf ("%d,%d,", v1, v2);
//fprintf (data, "%d,%d,", v1, v2);
}
printf ("\n");
//fprintf (data, "\n");
}
}
}
}
}
fclose (data);
}
so, when i click the button which calls this slot, it will never let me use the gui again.
This works in terminal.
thanks in advance.
Instead of your own select, you should use QSocketNotifier class and give your own file handles for Qt event loop.
You can also use this overload of QFile::open to turn your socket into a QIODevice instance.
Third choice is to put your own select loop into a different thread, so it does not block the Qt main event loop. But that is going to bring quite a lot of extra complexity, so I'd do that only as a last resort.
You are running the while loop in the same thread as the GUI so the event queue is blocked. You have two choices:
During the loop, call QCoreApplication::processEvents(). This forces the event queue to be processed.
Separate the while loop logic into it's own thread.
The first one is much simpler, but is generally considered inefficient, as just all about all computers have multiple cores.