How to control a 4 DOF robotic arm using Ardunio? - arduino

I recently bought a 4 DOF (Degree Of Freedom) robotic arm kit. I successfully assembled it and now I want to program the arduino to control it.
I know how to make the servos work using arduino but could not figure out how to move the hand to specific positions.
I tried manually creating a two dimensonal array with rotational values for each motor in degrees. This works but it is very hard to get the values and create the array. Currently I adjusted the values by trial and error.
The array I created manually :
short first[] = { 180 , 80 , 0 , 90 };
short pos[][4] =
{
{ 180 , 80 , 00 , 85 },
{ 180 , 85 , 00 , 80 },
{ 180 , 90 , 00 , 75 },
{ 180 , 95 , 00 , 75 },
{ 180 , 100 , 0 , 70 },
{ 180 , 110 , 0 , 70 },
{ 180 , 115 , 0 , 70 },
{ 180 , 120 , 0 , 65 },
{ 180 , 125 , 0 , 65 },
{ 180 , 130 , 0 , 65 },
{ 180 , 135 , 0 , 65 },
{ 180 , 140 , 0 , 65 },
{ 180 , 145 , 0 , 65 },
{ 180 , 150 , 0 , 65 },
{ 180 , 150 , 0 , 70 },
{ 180 , 150 , 0 , 75 },
{ 180 , 150 , 0 , 80 },
{ 180 , 150 , 0 , 90 },
{ 180 , 145 , 0 , 90 },
{ 180 , 140 , 0 , 90 },
{ 180 , 135 , 0 , 90 },
{ 180 , 130 , 0 , 90 },
{ 180 , 125 , 0 , 90 },
{ 180 , 120 , 0 , 90 },
{ 180 , 115 , 0 , 90 },
{ 180 , 110 , 0 , 90 },
{ 170 , 110 , 0 , 90 },
{ 160 , 110 , 0 , 90 },
{ 150 , 110 , 0 , 90 },
{ 140 , 110 , 0 , 90 },
{ 130 , 110 , 0 , 90 },
{ 130 , 115 , 0 , 90 },
{ 120 , 120 , 0 , 90 },
{ 120 , 125 , 0 , 90 },
{ 120 , 130 , 0 , 90 },
{ 120 , 135 , 0 , 90 },
{ 120 , 137 , 0 , 90 },
{ 120 , 139 , 0 , 90 },
{ 120 , 140 , 0 , 85 },
{ 120 , 140 , 0 , 80 },
{ 120 , 140 , 0 , 75 },
{ 120 , 140 , 0 , 70 },
};
The complete code that I wrote :
/*
* claws - 90 close 75 open
* elbow - 0 to 100
* sholder - 30 to 180
*/
Servo Servos[4];
void setup()
{
Servos[0].attach(3);
Servos[1].attach(5);
Servos[2].attach(9);
Servos[3].attach(11);
reset();
run();
Servos[0].detach();
Servos[1].detach();
Servos[2].detach();
Servos[3].detach();
}
void run()
{
for(int i=0; i<sizeof(pos) / sizeof(short) /4 ; i++)
{
for(int j=3; j>=0; j--)
{
Servos[j].write(pos[i][j]);
delay(15);
}
delay(15);
}
for(int i=-1+ sizeof(pos) / sizeof(short) /4;i>=0 ; i--)
{
for(int j=3; j>=0; j--)
{
Servos[j].write(pos[i][j]);
delay(15);
}
delay(15);
}
delay(3000);
}
void reset()
{
for(int i=3; i>=0; i--)Servos[i].write(first[i]);
}
void loop(){}
I want some function to calculate the values of the array for any given coordinate or something like that.(That is the moves of each servo to position the end of the arm at that point)
Photo of the Arm :
Here is the product page of the actual arm :
https://www.amazon.in/gp/product/B07LDNY9J3/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1

I finally solved the problem ! I tried figuring out the inverse kinematics for the arms but I found out it is very hard and due to the uncertainty in the hardware it doesn't work good either. The actual solution was to use sensors. I put distance sensors (Ultra-sonic) on the arm so that I can measure distance between arm parts in real time. Since I know the length of each segment of the arm (I don't have to worry about uncertainty here.) and also the distance between them I can do simple trigonometry to calculate the coordinates of the tip of the arm. This means that I can simply use a feedback loop to position the arm with ineradicable accuracy and overcome the limitations of the Hardware.
I do understand that this is not the exact answer for the asked question but I found out from my experience that this method is the most suitable for the situation (When compared to the attempt according to the question).

Related

Css vars changes not simultaneously for nested elements

I have Vue 3 project with Pinia. I have store for theme
export const useThemeStore = defineStore('theme', {
state: () => ({
dark: false,
}),
getters: {
current(state) {
return state.dark ? Theme.dark : Theme.light
},
},
persist: true,
})
And I use it in my App.vue (with Pug templates) file like this
Head
html(:data-theme="theme.current")
Also I have styles like
html {
--col-white: 255 255 255;
--col-black: 22 25 33;
&[data-theme='dark'] {
--col-primary: 255 255 255;
--col-secondary: 230 236 245;
--col-page: 22 25 33;
--col-page-content: 116 140 171;
--col-success: 57 158 90;
--col-info: 58 133 199;
--col-warning: 255 127 17;
--col-danger: 255 27 28;
}
&[data-theme='light'] {
--col-primary: 22 25 33;
--col-secondary: 116 140 171;
--col-page: 255 255 255;
--col-page-content: 230 236 245;
--col-success: 57 158 90;
--col-info: 58 133 199;
--col-warning: 255 127 17;
--col-danger: 255 27 28;
}
}
And I have problem - all variables changes with delay from top to bottom in DOM nesting
Here's gif to understand

How to overcome Naive Bayes classification error

I downloaded the email files from my email account to classify them as a promotional mail or not. I am using Naive Bayes classifier for classification.
I am using the code given below
> classify.trip<- function(path, training.df, prior = 0.5, c=1e-6)
+ {
+ # Here, we use many of the support functions to get the
+ # trip file in a workable format
+ msg <- get.msg(path)
+ msg.tdm <- get.tdm(msg)
+ msg.tdm<-removeSparseTerms(msg.tdm,0.8)
+ msg.freq <- rowSums(as.matrix(msg.tdm))
+ # Find intersections of words
+ msg.match <- intersect(names(msg.freq), training.df$term)
+ # Now, we just perform the naive Bayes calculation
+ if(length(msg.match) < 1)
+ {
+ return(prior * c ^ (length(msg.freq)))
+ }
+ else
+ {
+ match.probs <- training.df$occurrence[match(msg.match, training.df$term)]
+ return(prior * prod(match.probs) * c ^ (length(msg.freq) - length(msg.match)))
+ }
+ }
> promo.test <-sapply(ptest.docs,
+ function(p) classify.trip(file.path(ptest.path, p), training.df = promo.df))
> promo.test
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
but it gives me the probability zero of all files

Decision tree in r

my dataset is :
x=data.frame(v1=c(97 , 97 , 85 , 84 , 90 , 80 , 81 , 90 , 80, 70, 90 , 90, 90 ,95 , 88 , 99),
+ v2=c(99 , 91 , 91 ,83 , 99 , 95 , 74 , 88 , 82 , 80 , 96 , 87 , 92 , 96 , 88, 95),
+ v3=c( 89 ,93 , 87 , 80 , 96 , 96 , 75 , 90 , 78, 86 , 92 ,88 , 80, 88 , 98 ,98),
+ v4=c( 89 , 97 ,91 , 86 , 95 , 95 , 89 , 88 , 75, 82 , 99, 92 , 95, 92 , 90, 98),
+ v5=c( 99 ,90 , 93 ,91 , 90 , 90 , 77 , 92 , 85, 76 , 90, 96 , 90, 90 , 90, 92))
> x
v1 v2 v3 v4 v5
1 97 99 89 89 99
2 97 91 93 97 90
3 85 91 87 91 93
4 84 83 80 86 91
5 90 99 96 95 90
6 80 95 96 95 90
7 81 74 75 89 77
8 90 88 90 88 92
9 80 82 78 75 85
10 70 80 86 82 76
11 90 96 92 99 90
12 90 87 88 92 96
13 90 92 80 95 90
14 95 96 88 92 90
15 88 88 98 90 90
16 99 95 98 98 92
I used rpart package to apply decision tree as follows :
# Classification Tree with rpart
library(rpart)
fit <- rpart(v5 ~ v1+v2+v3+v4,
method="class", data=x)
printcp(fit) # display the results
Classification tree:
rpart(formula = v5 ~ v1 + v2 + v3 + v4, data = x, method = "class")
Variables actually used in tree construction:
character(0)
Root node error: 9/16 = 0.5625
n= 16
CP nsplit rel error xerror xstd
1 0.01 0 1 0 0
> summary(fit) # detailed summary of splits
Call:
rpart(formula = v5 ~ v1 + v2 + v3 + v4, data = x, method = "class")
n= 16
CP nsplit rel error xerror xstd
1 0.01 0 1 0 0
Node number 1: 16 observations
predicted class=90 expected loss=0.5625 P(node) =1
class counts: 1 1 1 7 1 2 1 1 1
probabilities: 0.062 0.062 0.062 0.438 0.062 0.125 0.062 0.062 0.062
plot tree
# plot tree
plot(fit, uniform=TRUE,
+ main="Classification Tree ")
Error in plot.rpart(fit, uniform = TRUE, main = "Classification Tree ") :
fit is not a tree, just a root
text(fit, use.n=TRUE, all=TRUE, cex=.8)
Error in text.rpart(fit, use.n = TRUE, all = TRUE, cex = 0.8) :
fit is not a tree, just a root
what is my wrong while I applied rpart ? why it give me error with tree plot? how to fix this error Error :
fit is not a tree, just a root
You use method="class" if you are building a classification tree and method="anova" if you are building a regression tree. It looks like you have a continuous response, so you should be building a regression tree (i.e. method="anova").
You are using the RPART's default control parameters. With your data set RPART is unable to adhere to default values and create a tree (branch splitting)
rpart.control(minsplit = 20, minbucket = round(minsplit/3), cp = 0.01,
maxcompete = 4, maxsurrogate = 5, usesurrogate = 2, xval = 10,
surrogatestyle = 0, maxdepth = 30, ...)
Adjust the control parameters according to the data set.
e.g :
t <- rpart(formula = v5 ~ v1 + v2 + v3 + v4, data = x, method = anova",control =rpart.control(minsplit = 1,minbucket=1, cp=0))
But be aware this could create an over fitting decision tree.
I ran the following code with your x data frame and got a tree as shown below:
library(rpart)
library(rattle)
library(rpart.plot)
library(RColorBrewer)
fit <- rpart(v5 ~ v1+v2+v3+v4,
method="anova",
data=x,
control = rpart.control(minsplit = 6, cp = 0.01))
fancyRpartPlot(fit) #from RColorBrewer package
Note that your method should be anova as v5 is a continuous variable, and you have to override the control parameters control = rpart.control(...) to adjust the depth of the tree.

Qt: How to implement "per minute" Timer? Better option to avoid misfire and double-fire?

I am using Qt5 on Windows7 platform.
In my current app I need a timer to fire every minute ("per minute"), from minute 00 to 59...
I have experimented various ideas, but my (previous) solutions had some issues like: misfire (no timeout triggered for a certain minute) or double-fire (timeout triggered twice for the same minute!).
Finally, I currently reached to this implementation:
static QTimer timer;
static int GetInterval()
{
QDateTime now(QDateTime::currentDateTime());
return ((60 - now.time().second()) * 1000 - now.time().msec());
}
void TEST_TIMER(void)
{
QObject::connect(&timer, &QTimer::timeout, []()
{
qDebug() << " Triggered! " << QDateTime::currentDateTime().time().minute()
<< QDateTime::currentDateTime().time().second()
<< QDateTime::currentDateTime().time().msec();
timer.start(GetInterval());
} );
timer.start(GetInterval());
}
And here is the output:
Triggered! 34 59 550
Triggered! 35 0 3
Triggered! 36 0 15
Triggered! 37 0 28
Triggered! 38 0 41
Triggered! 39 0 54
Triggered! 40 0 68
Triggered! 41 0 82
Triggered! 42 0 97
Triggered! 43 0 109
Triggered! 44 0 123
Triggered! 45 0 137
Triggered! 46 0 149
Triggered! 47 0 165
Triggered! 48 0 178
Triggered! 49 0 192
Triggered! 50 0 205
Triggered! 51 0 217
Triggered! 52 0 231
Triggered! 53 0 244
...
Seems ok, except the first line: Triggered! 34 59 550 :( Why?
Also, why is there that up-drift of about 12-13 msecs/minute?.
So, not being expert in this matter I prefer to ask:
Is this implementation ok? Can it be improved to avoid unpleasant situations like double-fire and/or misfire?
From QTimer description (Qt::CoarseTimer being the default):
For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up
earlier than expected, within the margins for those types: 5% of the
interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
So with a 5% accurary, your first shot can be much earlier than expected, and that explains:
Triggered! 34 59 550
Triggered! 35 0 3
If the timer shots (just) before the 0 minute, it will shoot again to align to the minute that's not yet reached, even if it's a few milliseconds away.
If you use a Qt::PreciseTimer instead, it will never time out earlier than expected, so you won't have this problem (pad the delay with a few ms to be sure).
The Qt::CoarseTimer also probably explains the small drift you're seeing, as nothing states that the error margin is random.
I need a timer to fire every minute
Why not keep things simple?
QTimer* pTimer = new QTimer;
connect(pTimer, &QTimer::timeout, [=](){
// do something
};
// fire every 60 seconds
// 1 * 1000 is every second
pTimer->Start(1 * 1000 * 60)
Note that a timer will keep firing, unless you set setSingleShot(true), stop the timer, or delete it.

How would I write a test to cover lines of code that fall through the cracks, sample provided

I am trying to acheive 100% code coverage, but I cannot determine how to cover lines like #57 below. It is simply an ending }. I have these lines throughout all of my code, as well as lines like, } else {, but they are not covered, nor marked as dead code.
How would I write a test to cover these lines?
34 : public function addAction() {
35 :
36 2 : $form = new Roles_Form_Add();
37 :
38 2 : if ($this->getRequest()->isPost()) {
39 :
40 1 : if ($form->isValid($this->getRequest()->getPost())) {
41 :
42 1 : $clean = $form->getValues();
43 :
44 1 : $roleService = new Roles_Service_Role();
45 :
46 1 : $role = $roleService->fetchNew();
47 1 : $role->setFromArray($clean)
48 1 : ->save();
49 :
50 1 : $this->_helper->flashMessenger('A new role has been added.');
51 :
52 1 : $this->_helper->redirector('view','role','roles',array('id'=>$role->id));
53 1 : return;
54 :
55 : }
56 :
57 0 : }
58 :
59 1 : $form->setAction($this->_helper->url('add','role','roles'));
60 :
61 1 : $this->view->addRoleForm = $form;
62 :
63 1 : }
64 :
public function testAddAction() {
$this->dispatch('/roles/role/add');
$this->assertModule('roles');
$this->assertController('role');
$this->assertAction('add');
$this->assertQuery('form#addRole input#name');
}
public function testAddActionWithPost() {
$this->getRequest()->setMethod('POST')
->setPost('name','Test');
$this->dispatch('/roles/role/add');
$this->assertRedirectTo('/roles/role/view/id/1');
}
From a first glimpse of the code, I'd say that line 40 (if ($form->isValid($this->getRequest()->getPost())) {) always evaluates to true in your tests and therefore the function addAction is always left with the return; statement in line 53.

Resources